简体   繁体   English

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

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

Test.java: 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. 但是我仍然期望编译器有足够的信息来编译上面的代码。

You declared 你声明了

Wrapper test = stack.pop();

You are using Wrapper as a raw type . 您正在使用Wrapper作为原始类型 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 ArrayListiterator()方法声明为

public Iterator<E> iterator() {

where E is ArrayList 's type parameter. 其中EArrayList的类型参数。 Its erasure becomes 它的擦除变成了

public Iterator iterator() {

The Iterator#next() method is declared as Iterator#next()方法声明为

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 . 您隐式(通过for-each循环)尝试将Object类型的值分配给Wrapper类型的引用。

You didn't type your Wrapper , 你没有输入你的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. 你应该有Wrapper<TYPE> ,其中TYPE是合适的。

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. 您在代码中使用原始类型Wrapper ,在这种情况下,编译器无法使用所有泛型类型信息。 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. 因此,编译器将ArrayList<Wrapper>看作只是ArrayList ,这就是为什么当你迭代它时,你会得到Object类型值而不是Wrapper类型。

See JLS § 4.8 - Raw Types for more details: 有关更多详细信息,请参阅JLS§4.8 - 原始类型

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. 未从其超类或超接口继承的原始类型C的构造函数(第8.8节),实例方法(第8.4节,第9.4节)或非静态字段(第8.3节)M的类型是对应的原始类型在对应于C的通用声明中擦除其类型

Also See: 另见:

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM