简体   繁体   English

返回类型是擦除的一部分吗?

[英]Is return type part of the erasure?

Can somebody explain why the second class does not compile? 有人可以解释为什么第二类不编译?

1 Compiles fine using javac and JDK 6 (Eclipse will complain this code) 1使用javac和JDK 6编译好(Eclipse会抱怨此代码)

public class SameSignatureMethods {
    public <T extends String> Boolean test()
    {
        return true;
    }

    public <T extends Character> Double test() 
    {
        return 1d;
    }
}

2 A little change to that example, and compilation fails with the following error: 2对该示例稍作更改,编译失败,并出现以下错误:

name clash: <T>test() and <T>test() have the same erasure

The only change is return type on the method: 唯一的变化是方法的返回类型:

public class SameSignatureMethods {
    public <T extends String> Boolean test()
    {
        return true;
    }

    public <T extends Character> Boolean test() {
        return true;
    }
}

thats how main method for first class will look: 这就是第一类的主要方法看起来如何:

public static void main(String[] args) {
    SameSignatureMethods m = new SameSignatureMethods();
    System.out.println("m.<Character>test()=" + m.<Character>test());
    System.out.println("m.<String>test()=" + m.<String>test());
}

So, the JDK compiler compiles the first version but not the second, while the Eclipse compiler compiles neither of the two versions. 因此,JDK编译器编译第一个版本但不编译第二个版本,而Eclipse编译器编译两个版本中的任何一个版本。

From the viewpoint of Java byte code, the first version contains two different methods (after type erasure), namely public java.lang.Boolean test() and public java.lang.Double test() , which is perfectly valid. 从Java字节代码的角度来看,第一个版本包含两种不同的方法(在类型擦除之后),即public java.lang.Boolean test()public java.lang.Double test() ,这是完全有效的。 The JDK compiler and the Eclipse compiler sometimes generate such methods when you override generic methods, but those are then marked as synthetic bridge methods. 当您覆盖泛型方法时,JDK编译器和Eclipse编译器有时会生成此类方法,但这些方法随后会标记为合成桥接方法。

The second version would contain two methods with the same signature (after type erasure), which is not allowed in Java byte code. 第二个版本将包含两个具有相同签名的方法(在类型擦除之后),这在Java字节代码中是不允许的。 Therefore the JDK compiler cannot generate such a class file. 因此JDK编译器无法生成这样的类文件。 I just edited a class file with a hex editor to create a class with such methods, and upon starting the program, I get this error: 我刚刚使用十六进制编辑器编辑了一个类文件来创建一个具有这些方法的类,并且在启动程序时,我收到此错误:

Exception in thread "main" java.lang.ClassFormatError: Duplicate method name&signature in class file SameSignatureMethods
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClassCond(Unknown Source)
    at java.lang.ClassLoader.defineClass(Unknown Source)
    at java.security.SecureClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.defineClass(Unknown Source)
    at java.net.URLClassLoader.access$000(Unknown Source)
    at java.net.URLClassLoader$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.net.URLClassLoader.findClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
    at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)
    at java.lang.ClassLoader.loadClass(Unknown Source)
Could not find the main class: SameSignatureMethods.  Program will exit.

The class I started with looks like this. 我开始的课程看起来像这样。 I used String and Double because they have the same name length: 我使用String和Double因为它们具有相同的名称长度:

public class SameSignatureMethods {
    public  <T extends String> String test() {
        return null;
    }

    public  <T extends Double> Double test() {
        return null;
    }

    public static void main(String[] args) {
        System.out.println(new SameSignatureMethods().<Double>test());
    }
}

Then, using a hex editor, I changed the signature of the first method to public <T extends String> Double test() , in two places of the class file, one with the raw signature ()Ljava/lang/Double; 然后,使用十六进制编辑器,我将第一个方法的签名更改为public <T extends String> Double test() ,在类文件的两个位置,一个带有原始签名()Ljava/lang/Double; , one with the generic signature <T:Ljava/lang/String;>()Ljava/lang/Double; ,一个带有通用签名<T:Ljava/lang/String;>()Ljava/lang/Double; .

Sounds like you have managed to confuse your compiler terribly: 听起来你已经成功地混淆了你的编译器:

  • Return type is not part of the signature. 返回类型不是签名的一部分。 The compiler can't use return type to tell which method is being called. 编译器不能使用返回类型来告诉调用哪个方法。

  • In your example the generic stuff crammed into the method signature does not affect the return type anyway. 在您的示例中,无论如何,填充到方法签名中的泛型函数不会影响返回类型。

  • Also saying <T extends String> makes no sense, you can't extend a final type. 另外说<T extends String>毫无意义,你不能扩展最终类型。 (Hmm, this is just a warning, it does not stop compilation) (嗯,这只是一个警告,它不会停止编译)

You wonder why the second class doesn't compile, I wonder why the first class compiles. 你想知道为什么第二个类不编译,我想知道为什么第一个类编译。 As is, the first class compiles, albeit with a warning. 按原样,第一类编译,尽管有警告。 Taking out the pointy bracket stuff results in a 'Duplicate Method' error that ought to appear regardless. 取出尖括号的东西会导致出现“重复方法”错误,无论如何都应该出现。 Must be a compiler bug. 必须是编译器错误。

In the first class ( SameSignatureMethods ), the 2 methods at runtime return Boolean and Double , respectively. 在第一个类( SameSignatureMethods )中,运行时的2个方法分别返回BooleanDouble In the second class the methods both return Boolean . 在第二个类中,方法都返回Boolean

<T extends String> in front of a method definition does not mean that it is a return type. 方法定义前面的<T extends String>并不意味着它是一个返回类型。

Maybe you want to do something like this: 也许你想做这样的事情:

public <T extends String> T test()
{
    return obj;// obj could be a String
}

However, generic types are erased at runtime, and the method above would become 但是,泛型类型在运行时被擦除,并且上面的方法将变为

public Object test()
{
    return obj;// obj could be a String
}

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

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