没有类型作为方法参数的通用 – 无法解析它的字段类型
我们考虑一个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.list
是List
。
关于类型擦除的其他问题已被链接,从不同的角度处理问题。 在不知道我自己问题的答案的情况下,我没有看到连接,这就是为什么我不认为这个问题是重复的。
当使用Foo t
, t
是原始类型,因此其非静态非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
具有它。