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

我们考虑一个class级:

public class Foo { public List list = new ArrayList(); } 

我作为参数传递给方法。


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

 public void test(Foo t) { t.list.get(0).contains("test"); } 

并且t.list被视为List而这里一切正常:

 public void test(Foo t) { t.list.get(0).contains("test"); } 

t.listList


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

当使用Foo tt是原始类型,因此其非静态非inheritance成员(如上面代码中的list也是原始类型。 这里是Java语言规范的相关部分(见上面的链接):

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

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

  • 。 。 。

  • 原始类型R的非静态成员类型,它不是从R的超类或超级接口inheritance的。

和/或

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

只需将list声明为static ,它将被解释为符合预期的String List 用于测试

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

稍后在该页面上的建议 :

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

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

这就是Type Erasure的工作原理。

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

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

通过提供您提供有界类型,并将用于类型擦除。 编译器将识别contains因为String具有它。