Java泛型:在编译时进行类型检查,检查后擦除类型,保证运行期间类型安全。创建对象实例或者调用方法时才作为参数指定类型。
相关术语:(下图参考自Java3y https://www.zhihu.com/question/272185241)
E是形式类型参数,String是实际类型参数。
每个泛型都定义一个原生态类型,即不带任何实际类型参数。上述列表对应的原生态类型就是ArrayList。原生态类型会逃避泛型检查,失去类型安全性。(目前支持原生态类型是为了与以前的java版本兼容)
规则:
ArrayList<String> 是原生态类型ArrayList的子类型(类型擦除),但不是ArrayList<Obect>的子类型。这二者没有关系,虽然String是Object的子类型。
- Java泛型的类型参数之实际类型在编译时会被擦除,所以无法在运行时得知其类型参数的类型。
优点:
- 避免了从集合中获取对象时进行强制转换,编译器就知道是什么类型;
- 如果类型不安全,会在编译期间报错或警告,不会在运行时才抛出异常
数组与泛型
-
数组是协变的,泛型是不可变的。若Sub是Super的子类,则Sub[]是Super[]的子类。而对于泛型,则如规则1所述。
-
数组是具体化的,即运行时知道并检查类型元素。而泛型在运行时已经擦除了元素的类型信息。唯一可具体化的参数化类型是无限制的通配符类型,即用?代替类型参数。如List<?>
-
由上述两条可知, 数组提供了运行时的类型安全,而不提供编译时的类型安全。泛型反之。
-
不允许创建泛型数组。 下面这条语句是非法的。(String换成E同样非法)原因是类型不安全。
-
对于如下代码,使用数组,该代码会通过编译,到运行时才抛出ArrayStoreException;而使用列表,不会通过编译。因此可以考虑优先选择列表。
参考:Effective Java第二版