views:

75

answers:

1

Hi. 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

+7  A: 

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.

notnoop
That's really interesting. That explains why if you cast to A<?> instead of just A it works. In that case you are still using a typed class.
Shaun
+1 Thanks for this great answer. I removed my own answer, that was not as good as this one.
KLE
@Shaun, yup. Partially, it's matter of annoying you so to avoid using raw types!
notnoop
Thanks, that explains it. Btw, the reason it worked for the guy who tested it on 1.6.0_17 was a pebkac when pasting the code via msn/adium... The cast was removed, probably because of some formatting thing. My bad.
Kristian