javagenerics

Why this piece of java code with generics doesn't compile


Test.java:

import java.util.ArrayList;
import java.util.Stack;
import java.util.Iterator;

class Wrapper<T> {
    public T content;
    public ArrayList<Wrapper> children;
}

public class Test {
    public static void testing (Stack<Wrapper> stack) {
        Wrapper test = stack.pop();

        Iterator<Wrapper> itr = test.children.iterator();
        while (itr.hasNext()) {
            Wrapper item = itr.next();
            System.out.println(item.content);
        }

        ArrayList<Wrapper> canCompile = test.children;
        for (Wrapper child : canCompile) {
            System.out.println(child.content);
        }

        for (Wrapper child : test.children) {
            System.out.println(child.content);
        }
    }
} 

Error:

Test.java:25: error: incompatible types
        for (Wrapper child : test.children) {
                                 ^
  required: Wrapper
  found:    Object
Note: Test.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error

My question isn't how to get this code to work. But rather why this code as it stands doesn't compile. The above code uses generics in a way that's unorthodox, and it also yields compilation warnings. However I would still expect the compiler to have enough information to compile the above piece of code.


Solution

  • However I would still expect the compiler to have enough information to compile the above piece of code.

    No it doesn't. Because you didn't gave the compiler enough information.

    You are using a raw type Wrapper in your code, in which case, all the generic type information is not available to the compiler. So, the compiler sees ArrayList<Wrapper> as just ArrayList, and that is why when you iterate over it, you'll get back Object type values and not Wrapper type.

    See JLS § 4.8 - Raw Types for more details:

    The type of a constructor (§8.8), instance method (§8.4, §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 raw type that corresponds to the erasure of its type in the generic declaration corresponding to C.

    Also See: