I recently stumbled upon a piece of code that would not compile in my Eclipse due to the "same erasure" issue (looked very similar to this one). The guys who wrote the code assured me that it compiles in their local environment and their continuous integration and so I played along to emulate it.
Take a look at this snippet:
package com.mycompany.playground;
import java.util.ArrayList;
import java.util.Collection;
public class GenericsTest {
public static void main (String[] args) {
System.out.println(GenericsTest.doSomething(new ArrayList<A>()));
System.out.println(0 == GenericsTest.doSomething(new ArrayList<C>()));
}
public GenericsTest() {
}
public static String doSomething(Collection<A> listOfA) {
return "has done something to Collection<A>";
}
public static Integer doSomething(Collection<C> listOfC) {
return 0;
}
private class A {
}
private class C {
}
}
Eclipse Helios with 1.6.0_21 JDK as workspace default would not compile it and would complain that Method doSomething(Collection) has the same erasure doSomething(Collection) as another method in type GenericsTest. It would say the same about the other method.
Tried to force Eclipse to run it and saw: Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method doSomething(Collection) in the type GenericsTest is not applicable for the arguments (ArrayList).
Ok. That was to be expected. Now. If I go into my command line and run simple:
javac GenericsTest.java
it compiles. I checked 1.6.0_21 and 1.6.0_06 (the one the guys had in their environments) and neither complained. I copied the class files over to where Eclipse expected them and forced it to run it again.
It prints:
has done something to Collection<A>
true
If I replace the
System.out.println(0 == GenericsTest.doSomething(new ArrayList<C>()));
with
System.out.println(GenericsTest.doSomething(new ArrayList<C>()));
it would still compile without warnings from the command line but give the same "Unresolved compilation problem" when trying to run it.
Two questions here.
Did javac simply outsmart the built-in Eclipse compiler? Looks almost exactly like this previously asked question so I believe I know the answer. (by the way, how can I tell Eclipse to use javac instead?).
Why would javac silently compile what java will then fail to run (second scenario with the {0 ==} "hint" removed?
The question here is: Whenever you have 2 methods with the same name, they must have different signature. The signature considered here does not include return type so these two methods cannot be declared in the same class
int foo(A a)
float foo(A a)
In you example, you have two differents methods with distinct parameter types (Collection<A>
and Collection<C>
) but internally, when the compiler does its magic, generics ar considered Collection. This is what "same erasure" means.
I don't remember right now if all java versions show this behaviour, since I've been stuck with java 5 and java 6 for too much.
Hope it can be helpful.
According to Java specification, two methods should be distinguished by signature (name + parameter types), not return type. And the original code can be compiled due to a bug in JDK http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6182950 This bug has been fixed in some versions of Eclipse, that's why some of you cannot get it compiled in Eclipse. As to why the compiled code can actually work, you should understand that Java language does not equivalent to JVM byte code. In byte code you can have a whole lot of illegal Java names and yes, byte code distinguish methods by signature, return type, and probably some additional info.
Pavel, I think I faced with the same issue you described.
Today I was hacking with my own code and got the same different behavior for Eclipse's and Java's compilers. Though, it seems it's a known compiler issue.
Please refer to Bug 6182950 .
Thanks!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With