我们来考虑一个课程:
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.list是List<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对应的泛型声明中擦除其类型
刚刚宣布list的static,它会被解释为List的String预期(测试).
另一方面,声明Foo<?>不是原始类型,因此list也不被视为原始类型.
稍后在该页面上的建议:
原始类型的使用仅允许作为遗留代码兼容性的让步.在将泛型引入Java编程语言之后编写的代码中使用原始类型是非常不鼓励的.未来版本的Java编程语言可能会禁止使用原始类型.
注意:类型Erasure和生成的字节码在两种情况下都是相同的......
这就是Type Erasure的工作原理.
如果类型参数是无界的,则用泛型或对象替换泛型类型中的所有类型参数.因此,生成的字节码仅包含普通的类,接口和方法.
由于您的方法接受原始类型,因此编译器通过擦除类型来应用类型擦除String并将其替换为Object.这就是为什么contains没有被识别,因为Object没有那个方法调用.
通过提供<?>您提供的有界类型,将用于类型擦除.有编译器会承认contains,因为String有它.