没有类型作为方法参数的通用 - 无法解析它的字段类型

Nor*_*dar 13 java generics

我们来考虑一个课程:

public class Foo<T> {
    public List<String> list = new ArrayList<>();
}
Run Code Online (Sandbox Code Playgroud)

我作为参数传递给方法.


我有一个问题,理解为什么这里的类型String没有解决:

public void test(Foo t) {
    t.list.get(0).contains("test");
}
Run Code Online (Sandbox Code Playgroud)

并且在这里t.list处理的List<Object>一切都很好:

public void test(Foo<?> t) {
    t.list.get(0).contains("test");
}
Run Code Online (Sandbox Code Playgroud)

并且t.listList<String>.


关于类型擦除的其他问题已被链接,从不同角度处理问题.在不知道我自己的问题的答案的情况下,我没有看到连接,这就是为什么我不认为这个问题是重复的.

use*_*421 10

使用时Foo t,t是一个原始类型,因此它的非静态非继承成员(如list上面的代码)也是原始类型.这里是Java语言规范的相关部分(见上面的链接):

为了便于与非泛型遗留代码接口,可以使用参数化类型(第4.5节)的擦除(第4.6节)或者数组类型为参数化类型的数组类型(第10.1节)的擦除作为类型. .这种类型称为原始类型.

更准确地说,原始类型被定义为以下之一:

  • ...

  • 原始类型R的非静态成员类型,不是从R的超类或超级接口继承的.

和/或

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

刚刚宣布liststatic,它会被解释为ListString预期(测试).

另一方面,声明Foo<?>不是原始类型,因此list也不被视为原始类型.

稍后在该页面上的建议:

原始类型的使用仅允许作为遗留代码兼容性的让步.在将泛型引入Java编程语言之后编写的代码中使用原始类型是非常不鼓励的.未来版本的Java编程语言可能会禁止使用原始类型.

注意:类型Erasure和生成的字节码在两种情况下都是相同的......


Mur*_*göz 6

这就是Type Erasure的工作原理.

如果类型参数是无界的,则用泛型或对象替换泛型类型中的所有类型参数.因此,生成的字节码仅包含普通的类,接口和方法.

由于您的方法接受原始类型,因此编译器通过擦除类型来应用类型擦除String并将其替换为Object.这就是为什么contains没有被识别,因为Object没有那个方法调用.

通过提供<?>您提供的有界类型,将用于类型擦除.有编译器会承认contains,因为String有它.