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 foo
is a Foo<String>
, or
Foo.baz(List)
Foo.baz(ArrayList)
if foo
is a Foo
.
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 but Foo<T>.baz(ArrayList<Object>)
does not.
In the second case both functions match, and Foo.baz(ArrayList)
is more specific, so it is chosen.
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