0

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.

darenzou
  • 3
  • 1

3 Answers3

1

You declared

Wrapper test = stack.pop();

You are using Wrapper as a raw type. As such, at compile time, all methods and fields that have generic components appear as their erasure.

So

public ArrayList<Wrapper> children;

appears as

public ArrayList children;

The iterator() method of ArrayList is declared as

public Iterator<E> iterator() {

where E is ArrayList's type parameter. Its erasure becomes

public Iterator iterator() {

The Iterator#next() method is declared as

E next();

so its erasure in turn becomes

Object next();

You're implicitly (through the for-each loop) trying to assign a value of type Object to a reference of type Wrapper.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
1

You didn't type your Wrapper,

public static void testing (Stack<Wrapper> stack) // <-- Here

or

 Wrapper test = stack.pop(); // <-- or here.

And, that is why that isn't generic. You should have Wrapper<TYPE> where TYPE is appropriate.

Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
0

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:

Community
  • 1
  • 1
Rohit Jain
  • 209,639
  • 45
  • 409
  • 525