简体   繁体   English

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

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

i am spending a lot of time on learning Generic feature in Java.我花了很多时间学习 Java 中的通用功能。 I tried to read explanation in the following link: https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.html , and i didn't understand and also tried to understand the issue by the following link from the forum: Java Type Erasure: Rules of cast insertion?我尝试阅读以下链接中的解释: https://docs.oracle.com/javase/tutorial/java/generics/bridgeMethods.ZFC35FDC70D5FC69D269883A822C7A53E并试图从以下链接理解问题并从以下链接理解论坛: Java 类型擦除:强制插入规则? , but still things are far a way from being clear for me, and i also added a comment to post but i'm doubt if someone will refer to a comment because the post is very old. ,但对于我来说,事情还远未弄清楚,我还添加了一条评论,但我怀疑是否有人会参考评论,因为该帖子已经很旧了。

I'm trying to understand how the compiler knows which cast to make for method returned type when he makes the erasure.我试图了解编译器在进行擦除时如何知道为方法返回类型进行的转换。 In the book i'm learning from (Deital - Java How to Program), i think that something in the explanation is missing (maybe a typo).在我正在学习的书中(Deital - Java 如何编程),我认为解释中缺少某些内容(可能是错字)。 Is is written there: " In each case, the type of the cast for the return value is inferred from the types of the method arguments in the particular method call, because, according to the method declaration, the return type and the argument types match. As i understand the sentence, it says that the cast is according to the arguments that were send when the method was called. But if the methods doesn't get any argument. eg, if the method prototype is:那里写着:“在每种情况下,返回值的类型转换都是从特定方法调用中的方法 arguments 的类型推断出来的,因为根据方法声明,返回类型和参数类型匹配.据我理解这句话,它说演员是根据调用方法时发送的arguments.但是如果方法没有得到任何参数.例如,如果方法原型是:

public static <T extends Animal> T funcA ()

Now 3 different methods call the function.现在有 3 种不同的方法调用 function。 One wants to get a Dog a returned type ( Dog d = funcA() ), the second one wants to get Cat ( Cat c = funcA() ) and the last one wants to get Animal ( Animal A = funcA() ).一个想要得到一个 Dog 返回类型( Dog d = funcA() ),第二个想要得到 Cat ( Cat c = funcA() ),最后一个想要得到 Animal ( Animal A = funcA() )。 How does erasure decide which cast to make?擦除如何决定制作哪个演员表?

This doesn't actually have anything to do with erasure.这实际上与擦除没有任何关系。 The type is inferred from the call site : what type the caller is "actually expecting. Animal a = funcA() is equivalent to Animal a = MyClass.<Animal>funcA() , Dog d = funcA() is equivalent to Dog d = MyClass.<Dog>funcA() .类型从调用站点推断:调用者“实际期望的类型”。 Animal a = funcA()等价于Animal a = MyClass.<Animal>funcA()Dog d = funcA()等价于Dog d = MyClass.<Dog>funcA()

Whether this works at an implementation level does have something to do with erasure, and there isn't actually a valid implementation for funcA -- one that won't have compiler warnings, or equivalently, one that won't fail at runtime -- other than (something that boils down to) return null .这是否在实现级别上工作确实与擦除有关,并且实际上没有funcA的有效实现——一个不会有编译器警告的实现,或者等效地,一个不会在运行时失败的实现——除了(归结为) return null

based on the target types in the following statements基于以下语句中的目标类型

  • Dog d = funcA()狗 d = funcA()

  • Cat c = funcA()猫 c = funcA()

  • Animal A = funcA()动物 A = funcA()

the compiler is using Type Inference ( https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html ).编译器正在使用类型推断( https://docs.oracle.com/javase/tutorial/java/generics/genTypeInference.html )。 If you look at the examples in the Target Types section you will see something similar to what you are asking.如果您查看“目标类型”部分中的示例,您将看到与您所要求的内容相似的内容。

There are 3 different issues at hand:手头有3个不同的问题:

  • Type erasure of the actual method实际方法的类型擦除

  • Bridge methods when overriding inherited method覆盖继承方法时的桥接方法

  • Casting when calling the method调用方法时进行强制转换


You example is:你的例子是:

public static <T extends Animal> T funcA ()

That method cannot have anything to do with bridge methods, because it is static.该方法与桥接方法没有任何关系,因为它是 static。

Type erasure means that the compiler eliminates (erases) the generic type, so the code is compiled as-if you wrote:类型擦除意味着编译器消除(擦除)泛型类型,因此代码被编译,就像你写的一样:

public static Animal funcA ()

Because of that, when you then call the method, casting is added by the compiler:因此,当您随后调用该方法时,编译器会添加强制转换:

Dog d = (Dog) funcA()

As you can see, the compiled code doesn't have generic types, it is all "magic" implemented by the compiler, to pretend that generics actually exist.如您所见,编译后的代码没有泛型类型,这都是编译器实现的“魔术”,以假装 generics 确实存在。


Now, if you actually were interested in bridge methods and how erasure works, then let's look at the example in the link you provided.现在,如果您真的对桥接方法以及擦除的工作原理感兴趣,那么让我们看看您提供的链接中的示例。

In that article, the method in the base class is declared as:在那篇文章中,基础 class 中的方法声明为:

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

Erasure compiles that as: Erasure 将其编译为:

public class Node {
    public void setData(Object data)

In the subclass the method is declared as:在子类中,方法声明为:

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

Erasure compiles that as: Erasure 将其编译为:

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

Now a bridge method is added by the compiler, because the JVM needs an overriding method in the subclass with an Object parameter type:现在编译器添加了一个桥接方法,因为 JVM 需要在子类中使用Object参数类型的覆盖方法:

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

As you can see, the compiler once again added a cast.如您所见,编译器再次添加了强制转换。 I hope this answers your question about how the compiler knows which cast to make, when it makes the erasure.我希望这能回答您关于编译器如何知道要进行哪个强制转换以及何时进行擦除的问题。

There is no cast in the generic code at all.通用代码中根本没有演员表。 In Java object references are binary unchanged when a cast expression is evaluated.在 Java object 中,当评估转换表达式时,引用是二进制不变的。 Any reference type is always just object .任何引用类型始终只是object Everything else are guarantees from the compiler.其他一切都是编译器的保证。 So there is just no need for a cast in the generic code.所以没有必要在通用代码中进行强制转换。

In fact a cast generates only some code like实际上,演员表只生成一些代码,例如

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

However, Java allows to cast from untyped types to generic types.但是,Java 允许从无类型类型转换为泛型类型。 This can result in bad types returned by functions.这可能导致函数返回错误的类型。 It is up to the caller to deal with this situations.由调用者来处理这种情况。 The three callers knows their individual, expected type.三个调用者知道他们各自的预期类型。 So they can check for unexpected results (ie cast) when needed.因此,他们可以在需要时检查意外结果(即演员表)。

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

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