I have the following test class that uses generics to overload a method. It works when compiled with javac and fails to compile in Eclipse Helios. My java version is 1.6.0_2
Are you sure that Eclipse is also set to use Java 1.6?
It would be possible if javac had a bug in it. Javac is just software and is as liable to bugs as any other piece of software.
Plus, the Java Language Spec is very complex and a little bit vague in places so it could also be down to a difference in interpretation between the Eclipse guys and the javac guys.
I would start by asking this on the Eclipse support channels. They're normally very good at picking up these things and explaining why they think they're right or else admitting that they're wrong.
For the record, I think Eclipse is right here, too.
A point to keep in mind is that (all?, certainly some as for instance the NetBeans editor does this) static code analysis tools do not consider return type or modifiers (private/public etc.) as part of the method signature.
If that is the case, then with the aid of type erasure both getFirst
methods would get the signature getFirst(java.util.ArrayList)
and hence trigger a name clash...
Works for me in Eclipse Helios. Method selection occurs at compile time, and the compiler has enough information to do so.
Eclipse and javac use different compilers. Eclipse uses a third party compiler to turn your code into bytecodes for the Java VM. Javac uses the Java compiler than Sun publishes. Therefore it is possible that identical code produces slightly different results. Netbeans I believe uses Sun's compiler so check it in there as well.
The Java Language Specification, section 8.4.2 writes:
It is a compile-time error to declare two methods with override-equivalent signatures (defined below) in a class.
Two method signatures m1 and m2 are override-equivalent iff either m1 is a subsignature of m2 or m2 is a subsignature of m1.
The signature of a method m1 is a subsignature of the signature of a method m2 if either
m2 has the same signature as m1, or
the signature of m1 is the same as the erasure of the signature of m2.
Clearly, the methods are not override equivalent, since ArrayList<String>
isn't ArrayList
(the erasure of ArrayList<Integer>
).
So declaring the methods is legal. Also, the method invocation expression is valid, as there trivially is a most specific method, since there is only one method matching the argument types.
Edit: Yishai correctly points out that there is another restriction closely skirted in this case. The Java Language Specification, section 8.4.8.3 writes:
It is a compile time error if a type declaration T has a member method m1 and there exists a method m2 declared in T or a supertype of T such that all of the following conditions hold:
- m1 and m2 have the same name.
- m2 is accessible from T.
- The signature of m1 is not a subsignature (§8.4.2) of the signature of m2.
- m1 or some method m1 overrides (directly or indirectly) has the same erasure as m2 or some method m2 overrides (directly or indirectly).
Appendix: On ersure, and the lack thereof
Contrary to popular notion, generics in method signatures are not erased. Generics are erased in bytecode (the instruction set of the Java virtual machine). Method signatures are not part of the instruction set; they are written to the class file as specified in the source code. (As an aside, this information can also be queried at runtime using reflection).
Think about it: If type parameters were erased from class files entirely, how could the code completion in the IDE of your choice display that ArrayList.add(E)
takes a parameter of type E
, and not Object
(=the erasure of E
) if you didn't have the JDKs source code attached? And how would the compiler know to throw a compilation error when the static type of the method argument wasn't a subtype of E
?