Search code examples
javagenericsabstract-classparameterized

Strange behaviour with parameterized method on abstract class


Can someone tell my why this gives a compile error? I don't see why the cast to A in the second for-loop causes strings() to return a general List of Objects.

import java.util.ArrayList;
import java.util.List;

public class E {

    public static void main(String[] args) {
        for (String s : new D().strings()) {
            System.out.println("s = " + s);
        }
        for (String s : ((A) new D()).strings()) {
            System.out.println("s = " + s);
        }
    }

    static class D extends A<C> {
    }

    static abstract class A<T extends B> {
        List<String> strings() {
            return new ArrayList<String>() {{
                add("Foo");
                add("Bar!");
            }};
        }
    }

    static class B {
    }

    static class C extends B {
    }
}

Is this a Generics quirk?

Thanks, Kristian


Solution

  • In the line:

        for (String s : ((A) new D()).strings()) {
    

    You are casting to the raw type A, so you lose the type arguments information there. In Java, any use method or field on a raw type would also result in a raw type (even if all the parameterized information is available) -- well raw type or non-parameterized technically. So A.string() is viewed as the raw type List rather than List<String>.

    As the JSL specifies in Section 4.8:

    The type of a constructor (§8.8), instance method (§8.8, §9.4), or non-static field (§8.3) M of a raw type C that is not inherited from its superclasses or superinterfaces is the erasure of its type in the generic declaration corresponding to C. The type of a static member of a raw type C is the same as its type in the generic declaration corresponding to C.