繁体   English   中英

java 擦除如何决定返回类型的转换?

[英]How java erasure decided which cast to make to return type?

我花了很多时间学习 Java 中的通用功能。 我尝试阅读以下链接中的解释: https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.ZFC35FDC70D5FC69D269883A822C7A53E并试图从以下链接理解问题并从以下链接理解论坛: Java 类型擦除:强制插入规则? ,但对于我来说,事情还远未弄清楚,我还添加了一条评论,但我怀疑是否有人会参考评论,因为该帖子已经很旧了。

我试图了解编译器在进行擦除时如何知道为方法返回类型进行的转换。 在我正在学习的书中(Deital - Java 如何编程),我认为解释中缺少某些内容(可能是错字)。 那里写着:“在每种情况下,返回值的类型转换都是从特定方法调用中的方法 arguments 的类型推断出来的,因为根据方法声明,返回类型和参数类型匹配.据我理解这句话,它说演员是根据调用方法时发送的arguments.但是如果方法没有得到任何参数.例如,如果方法原型是:

public static <T extends Animal> T funcA ()

现在有 3 种不同的方法调用 function。 一个想要得到一个 Dog 返回类型( Dog d = funcA() ),第二个想要得到 Cat ( Cat c = funcA() ),最后一个想要得到 Animal ( Animal A = funcA() )。 擦除如何决定制作哪个演员表?

这实际上与擦除没有任何关系。 类型从调用站点推断:调用者“实际期望的类型”。 Animal a = funcA()等价于Animal a = MyClass.<Animal>funcA()Dog d = funcA()等价于Dog d = MyClass.<Dog>funcA()

这是否在实现级别上工作确实与擦除有关,并且实际上没有funcA的有效实现——一个不会有编译器警告的实现,或者等效地,一个不会在运行时失败的实现——除了(归结为) return null

基于以下语句中的目标类型

  • 狗 d = funcA()

  • 猫 c = funcA()

  • 动物 A = funcA()

编译器正在使用类型推断( https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html )。 如果您查看“目标类型”部分中的示例,您将看到与您所要求的内容相似的内容。

手头有3个不同的问题:

  • 实际方法的类型擦除

  • 覆盖继承方法时的桥接方法

  • 调用方法时进行强制转换


你的例子是:

public static <T extends Animal> T funcA ()

该方法与桥接方法没有任何关系,因为它是 static。

类型擦除意味着编译器消除(擦除)泛型类型,因此代码被编译,就像你写的一样:

public static Animal funcA ()

因此,当您随后调用该方法时,编译器会添加强制转换:

Dog d = (Dog) funcA()

如您所见,编译后的代码没有泛型类型,这都是编译器实现的“魔术”,以假装 generics 确实存在。


现在,如果您真的对桥接方法以及擦除的工作原理感兴趣,那么让我们看看您提供的链接中的示例。

在那篇文章中,基础 class 中的方法声明为:

public class Node<T> {
    public void setData(T data)

Erasure 将其编译为:

public class Node {
    public void setData(Object data)

在子类中,方法声明为:

public class MyNode extends Node<Integer> {
    public void setData(Integer data)

Erasure 将其编译为:

public class MyNode extends Node {
    public void setData(Integer data)

现在编译器添加了一个桥接方法,因为 JVM 需要在子类中使用Object参数类型的覆盖方法:

@Override
public void setData(Object data) {
    setData((Integer) data);
}

如您所见,编译器再次添加了强制转换。 我希望这能回答您关于编译器如何知道要进行哪个强制转换以及何时进行擦除的问题。

通用代码中根本没有演员表。 在 Java object 中,当评估转换表达式时,引用是二进制不变的。 任何引用类型始终只是object 其他一切都是编译器的保证。 所以没有必要在通用代码中进行强制转换。

实际上,演员表只生成一些代码,例如

if (!(obj instanceof desiredtype))
    throw new ClassCastException();

但是,Java 允许从无类型类型转换为泛型类型。 这可能导致函数返回错误的类型。 由调用者来处理这种情况。 三个调用者知道他们各自的预期类型。 因此,他们可以在需要时检查意外结果(即演员表)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM