为什么这段带有泛型的java代码无法编译

时间:2014-02-04 20:06:18

标签: java generics compiler-construction

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);
        }
    }
} 

错误:

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

我的问题不是如何让这段代码工作。但是为什么这个代码不能编译。上面的代码以非正统的方式使用泛型,并且它还产生编译警告。但是我仍然期望编译器有足够的信息来编译上面的代码。

3 个答案:

答案 0 :(得分:1)

你宣布了

Wrapper test = stack.pop();

您使用Wrapper作为raw type。因此,在编译时,所有具有通用组件的方法和字段都显示为其擦除。

所以

public ArrayList<Wrapper> children;

显示为

public ArrayList children;

iterator()的{​​{1}}方法声明为

ArrayList

其中public Iterator<E> iterator() { E的类型参数。它的删除变得

ArrayList

public Iterator iterator() { 方法声明为

Iterator#next()

所以它的擦除反过来变成

E next();

您隐式(通过for-each循环)尝试将类型Object next(); 的值分配给类型为Object的引用。

答案 1 :(得分:1)

您没有输入Wrapper

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

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

而且,这就是为什么这不是通用的。您应该Wrapper<TYPE> TYPE是合适的。

答案 2 :(得分:0)

  

但是我仍然期望编译器有足够的信息来编译上面的代码。

不,不。因为你没有给编译器足够的信息。

您在代码中使用原始类型Wrapper,在这种情况下,编译器无法使用所有泛型类型信息。因此,编译器将ArrayList<Wrapper>视为ArrayList,这就是为什么当您迭代它时,您将返回Object类型值,而不是Wrapper类型。< / p>

有关详细信息,请参阅JLS § 4.8 - Raw Types

  

未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是原始的在与C对应的泛型声明中对应于其类型擦除的类型。

另见: