开发者

Is return type part of the erasure?

开发者 https://www.devze.com 2023-01-26 15:27 出处:网络
Can somebody explain why the second class does not compile? 1 Compiles fine using javac and JDK 6 (Eclipse will complain this code)

Can somebody explain why the second class does not compile?

1 Compiles fine using javac and JDK 6 (Eclipse will complain this code)

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

    public <T extends Character> Double test() 
    {
        return 1开发者_高级运维d;
    }
}

2 A little change to that example, and compilation fails with the following error:

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.

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. 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.

The second version would contain two methods with the same signature (after type erasure), which is not allowed in Java byte code. Therefore the JDK compiler cannot generate such a class file. 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:

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;, one with the generic signature <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. (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. In the second class the methods both return Boolean.

<T extends String> in front of a method definition does not mean that it is a return type.

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
}
0

精彩评论

暂无评论...
验证码 换一张
取 消