如果不明白为什么要使用泛型,使用泛型的好处,以及泛型类,泛型接口,泛型方法等知识,请移步泛型基础一
通配符
上界通配符
上界通配符就是限制类型参数是某个类本身或者是其子类。
例如
public void dealData2(List<? extends Number> data) {
/**
*
*/
}
下界通配符
下界通配符:传入的泛型类型必须是“?”后面指定类型的父类,包括超类Object,以及它自身。
public void dealData(List<? super Number> data) {
/**
*
*/
}
无界通配符
无界通配符,就是参数可以是任意类型。
有两种情况,无界通配符是一种有用的方法:
1、如果你正在编写可以使用 Object 类中提供的功能来实现的方法。
2、当代码使用泛型类中不依赖于类型形参的方法时。例如,List.size 或 List.clear。实际上,Class<?> 经常被使用,因为 Class<T> 中的大多数方法都不依赖于 T。
下面是不使用通配符和使用无界通配符的区别。
/**
* 不使用通配符
*
* @param dataList
*/
public void printData(List<Object> dataList) {
for (Object element : dataList) {
}
}
我们可以在测试方法中报错了。
不适用通配符.png
是因为List<Integer>不是List<Object>的子类,而printData方法中需要的是List<Object>类型,所以会报错。
我们看下使用通配符的情况:
使用通配符.png
可以看到使用通配符之后是没有报错的。
通配符使用原则
public void test() {
List<String> src = new ArrayList<>();
List<String> dest = new ArrayList<>();
//public static <T> void copy (List < ? super T > dest, List < ? extends T > src)
Collections.copy(dest, src);
}
我们可以把变量分为In变量和Out变量。
In变量是提供数据,例如上例中的src。src参数提供要复制的数据,所以是In参数。
Out变量保存数据以供其他地方使用,例如上例中的dest。dest参数接收数据,所以是Out参数。
通配符的使用指南:
1、In变量是使用上界通配符定义,使用extends关键字。
2、Out变量是使用下界通配符定义,使用super关键字。
3、如果可以使用Object类中定义的方法访问In变量,请使用无界通配符。
4、在代码需要访问In和Out变量的情况下,不要使用通配符。
对泛型的限制
无法使用基本数据类型实例化泛型类型
原则一.pngType argument cannot be of primitive type
类型参数不能是基元类型
无法创建类型形参的实例
泛型不能创建实例,是因为不知道泛型具体的类型
原则二.png
Type parameter 'T' cannot be instantiated directly
类型参数'T'不能直接实例化
无法声明类型为类型形参的静态字段
翻译一下就是用类型形参声明的成员变量不能用static修饰。
原则三.png
类的静态字段是类的所有非静态对象共享的类级变量。因此,不允许使用类型形参的静态字段。考虑以下类:
public class MobileDevice<T> {
private static T os;
// ...
}
如果允许类型形参的静态字段,则以下代码将混淆:
MobileDevice<Smartphone> phone = new MobileDevice<>();
MobileDevice<Pager> pager = new MobileDevice<>();
MobileDevice<TabletPC> pc = new MobileDevice<>();
因为静态字段 os 由 phone,pager 和 pc 共享,所以 os 的实际类型是什么?它不能同时为 Smartphone,Pager 和 TabletPC。因此,你无法创建类型形参的静态字段。
不能使用参数化类型进行类型转换或者使用instanceof
原则四.pngIllegal generic type for instanceof
instanceof的泛型类型不合法
原则四-1.png
Inconvertible types; cannot cast 'java.util.List<java.lang.Integer>' to 'java.util.List<java.lang.Number>'
不可转换的类型;不能将'java.util.List<java.lang.Integer>'转换为'java.util.List<java.lang.Number>
无法创建参数化类型的数组
泛型不能是数组,是因为数组具有协变的性质。也就是说
如果A extends B
则 A[]也是B[]的子类。
如果数组是泛型的话,在泛型擦除之后就不满足A[]是B[]的子类了。
网友评论