1

我有以下通用类:

import java.util.ArrayList;
import java.util.List;

public class GenericRaw<T> {
    public List<String> get() {
         return new ArrayList<>();
    }
}

让我们考虑一下它的使用情况:

public class Usage {
    public void doSomething() {
        GenericRaw base = new GenericRaw();
        for (String x : base.get()) {   }
    }
}

对于此代码,Idea 不会给出任何编译错误,但 Java 编译器本身会:

java:需要不兼容的类型:java.lang.String 找到:java.lang.Object

可在 JDK 1.6.0_33 和 JDK 1.7.0_17 上重现。

有人可以帮我解释这个问题吗?

我的调查结果。可以成功编译以下变体:

public void doSomething() {
    GenericRaw<?> base = new GenericRaw();
    for (String x : base.get()) {   }
}

甚至:

public void doSomething() {
    GenericRaw base = new GenericRaw();
    List<String> list = base.get();
    for (String x : list) {   }
}
4

1 回答 1

3

有人可以帮我解释这个问题吗?

当然。它遵循 JLS 在第 4.8 节中对原始类型的描述:

为了方便与非通用遗留代码的接口,可以使用参数化类型(§4.5)的擦除(§4.6)或元素类型为参数化类型的数组类型(§10.1)的擦除作为类型. 这种类型称为原始类型。

擦除GenericRaw<T>

public class GenericRaw {
    public List get() { ... }
}

因为:

类型擦除还将构造函数或方法的签名(第 8.4.2 节)映射到没有参数化类型或类型变量的签名。构造函数或方法签名 s 的擦除是由与 s 相同的名称和 s 中给出的所有形式参数类型的擦除组成的签名。

如果构造函数或方法的签名被擦除,构造函数或方法的类型参数(第 8.4.4 节)和方法的返回类型(第 8.4.5 节)也会被擦除。

于 2013-04-02T18:22:47.067 回答