18

I've run into an issue in Java's Generics in which the same code will compile and work fine in Java 6, but will fail to compile because of the same erasure in Java 5. I have a file TestErasure.java that has an overloaded method, called "method":

import java.util.ArrayList;
import java.util.List;

public class TestErasure {
 public static Object method(List<Object> list) {
     System.out.println("method(List<Object> list)");
     return null;
 }

 public static String method(List<String> list) {
     System.out.println("method(List<String> list)");
     return null;
 }

 public static void main(String[] args) {
     method(new ArrayList<Object>()); 
     method(new ArrayList<String>()); 
 }
}

In Java 5, I get the expected compilation error, stating that the erasure of "method" is the same:

$ javac -version
javac 1.5.0_19
$ javac TestErasure.java
TestErasure.java:10: name clash: method(java.util.List<java.lang.String>) and method(java.util.List<java.lang.Object>) have the same erasure
        public static String method(List<String> list) {
                             ^
TestErasure.java:17: method(java.util.List<java.lang.Object>) in TestErasure cannot be applied to (java.util.ArrayList<java.lang.String>)
      method(new ArrayList<String>()); 
            ^
2 errors

However, Java 6 is able to compile and run this same code.

$ javac -version
javac 1.6.0_16
$ javac TestErasure.java
$ java TestErasure
method(List<Object> list)
method(List<String> list)

Based upon my current understanding of erasures (thanks to Jon Skeet and Angelika Langer), I actually expected the compilation error as thrown by Java 5 (unless something changed in how Java handled Generics--which I can not find on the Java 6 release notes). In fact, if I modify the return type of one of the overloaded methods:

public static Object method(List<Object> list) ...
public static Object method(List<String> list) ...

Java 6 also fails to compile because of the same erasures:

$ javac TestErasure.java TestErasure.java:5: name clash: method(java.util.List<java.lang.Object>) and method(java.util.List<java.lang.String>) have the same erasure
     public static Object method(List<Object> list) {
                          ^
TestErasure.java:10: name clash: method(java.util.List<java.lang.String>) and method(java.util.List<java.lang.Object>) have the same erasure
     public static Object method(List<String> list) {
                          ^
2 errors

It appears as if the return type in Java 6 somehow influences the selection of which overloaded method to use?

Can someone shed light on why the first example works in Java 6--it seems to go against the stated handling of overloaded generic methods?

More info:

Per David's suggestion, the original example, complied by javac 1.6, will run under the java 1.5:

$ javac -target 1.5 TestErasure.java
$ java -version
java version "1.5.0_19"
$ java TestErasure 
method(List<Object> list)
method(List<String> list)
Community
  • 1
  • 1
John Paulett
  • 15,596
  • 4
  • 45
  • 38
  • The (erased) return type is part of the method signature in all versions of Java. – Tom Hawtin - tackline Sep 16 '09 at 22:17
  • The return type is part of the method descriptor, but not the method signature, correct? http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#What%20is%20a%20method%20signature? – John Paulett Sep 16 '09 at 22:25
  • 1
    @Tom - I believe you are mistaken - "Definition: Two of the components of a method declaration comprise the method signature—the method's name and the parameter types." From http://java.sun.com/docs/books/tutorial/java/javaOO/methods.html . The method signature must be unique for method overloading to work, and they do not rely on the return type (for Java, at least). – weiji Sep 16 '09 at 22:39
  • 2
    Interestingly, with earlier "point" releases of Java 5, this works for me. I tried both 1.5.0_11 and 1.5.0_13, and got the same results you see with Java 6. – Matt Solnit Sep 16 '09 at 22:50
  • My terminology is probably wrong. But from a byte code perspective they type of the return and of the parameters are as important as each other. – Tom Hawtin - tackline Sep 16 '09 at 23:09
  • 1
    What happens if you try to use the compiled code from Java 5? And/or compile with `-target 1.5`? – David Moles Sep 17 '09 at 10:32
  • @David Moles, I've updated the post. Java 5 will run the code compiled by 6. – John Paulett Sep 17 '09 at 13:29
  • 1
    Wow. I wonder how big a can of worms it would be if instead of fixing the bug, they changed the spec? – David Moles Sep 22 '09 at 07:33

1 Answers1

8

Found these bugs on Sun, which I think is what you're describing:

http://bugs.sun.com/view_bug.do?bug_id=6182950
http://bugs.sun.com/view_bug.do?bug_id=6730568

JRL
  • 76,767
  • 18
  • 98
  • 146
  • This bug seems to be exhibiting in Netbeans 6.9. https://netbeans.org/bugzilla/show_bug.cgi?id=187859 – Brian Harris Jun 24 '10 at 19:00
  • Changeset db77bf6adb53 (23 October 2008) against the OpenJDK 7 code contains the fix: http://hg.openjdk.java.net/jdk7/build/langtools/rev/db77bf6adb53. – seh Oct 12 '10 at 22:12