Java类型的擦除机制
泛型是在JDK5引入的特性。它允许我们定义的类和接口的时候使用类型参数。它被广泛运用在java集合框架中。类型擦出概念是关于泛型是最容易困惑的部分之一。本文将教你如何使用她。
1.一个常见错误
在下面的例子,accept 方法接受了一个Object集合来作为参数,在main方法中调用却是使用String的集合。它能正常调用吗?
|
|
这看起来是否没什么问题,因为Object明显是String的超类。但是,这代码是不可能正常的,编译都不会通过的,在accept(al);这行是会有错误的。
accept(ArrayList < Object > )
方法和Main中调用是不一致的(ArrayList < String > )
。
2. List < Object >
vs. List < String >
这原因是因为类型擦出。注意:java泛型是编译级别的。在运行时由编译器生成的字节码是不包含泛型的类型信息的。
编译后,不管是Object的List还是String的List都会变成List,同时Object/String类型在JVM中都是不可访问的。在编译阶段,编译器发现它们不相同,使用报了一个编译错误。
3. 通配符和有界通配符
List< ? >
- List可以包含任何类型
|
|
必须记住,泛型是在编译时期的。在上面的例子中,不是我们没注意,我们不能给al添加任何类型。为了让其能添加,你可以使用通配符。
List< Object > - List 能包括 Object 或者 其子类
List< ? extends Number > - List 能包括Number及其子类
List< ? super Number > - List 能包括 Number 及其父类
4.比较
现在我们知道ArrayList < String >
并不是ArrayList < Object >
的子类。作为对比,你应该知道,如果两个泛型类型具有相同的参数,它们的继承关系是真正的。比如ArrayList < String >
是Collection< String>
的子类。
数组是不同的。他们在运行时知道执行它们的元素类型。这就是所谓的具体化。比如Object[] objArray
是String[] strArr
的父类。如果您尝试将字符串保存到整数的数组,你会在运行时得到异常ArrayStoreException。
延伸阅读
- 1.通配符
- 2.Java泛型与类型擦除
- 3.泛型陷阱