Search code examples
javagenericstype-parameter

Java two level generics strange behaviour


I have the following logic


public class Why {

    public static void main(String[] args) {
        Gen<A> gen = new Gen<>();
        gen.m(new A()); //eeeeeeeeee A
    }
}

class A {}

class B extends A {}

class C extends A {}

class Gen<E> {
    Test test = new Test();

    public void m(E e) {
        test.test(e);
    }
}

class Test {

    public <E extends A> void test(E e) {
        System.out.println("XXXXXXXXXX " + e.getClass().getSimpleName());
    }

    public <E> void test(E e) {
        System.out.println("eeeeeeeeee " + e.getClass().getSimpleName());
    }

}

the output for main means the compiler picks the second method in Test, is it strange or I missed something? shouldn'd java know the actual class for Gen#test?


Solution

  • Method overload resolution happens at compile-time.

    When the compiler is compiling Gen<E>, it doesn't know anything about E, i.e. it cannot guarantee that E extends A, so it has to call the overload of test with <E>.

    If you remove that overload of test(), you'll get a compile error, since the other one is not compatible at all:
      The method test(E extends A) in the type Test is not applicable for the arguments (E)

    To make it call the other one, change to Gen<E extends A>.