Consider this example:
import java.util.*;
class Foo<T> {
public int baz(List<String> stringlist) { return 1; }
public int baz(ArrayList<Object> objectlist) { return 2; }
public static void main(String[] args) {
Foo<String> foo = new Foo<String>(); // (A)
//Foo foo = new Foo(); // (B)
System.out.println(foo.baz(new ArrayList<String>()));
}
}
Why does it print 1 in (A), but 2 with (B)?
I know how method resolution works, so no need to explain that to me.
I want to know the deeper motivation behind this “feature”.
Why is there no erasure warning about it? (There is just one about Foo foo = new Foo().)
Why does method resolution use erased semantics although the generic type is given?
It’s because when the compiler is resolving overloads, it considers each method as either generic or non-generic, never a mixture of the two, so the candidates are:
Foo<T>.baz(List<String>)Foo<T>.baz(ArrayList<Object>)if
foois aFoo<String>, orFoo.baz(List)Foo.baz(ArrayList)if
foois aFoo.There is no such thing as
Foo.baz(List<String>). Either all type parameters are considered or none are. (I am not aware of this being explicitly stated in the JLS, but it makes sense since treating a generic method as if it were the raw equivalent is a backwards-compatibility feature.)In the first case,
Foo<T>.baz(List<String>)matches butFoo<T>.baz(ArrayList<Object>)does not.In the second case both functions match, and
Foo.baz(ArrayList)is more specific, so it is chosen.