1. java之泛型
泛型的本质即参数化类型,顾名思义,就是将原本的类型参数化,类似于方法中的变量参数,此时类型也定义为参数类型,然后在使用或者调用时再传入具体的类型,即泛型将参数类型的确定推迟到了创建对象或者调用方法时。
2. 为什么要使用泛型
常见的例子,当不使用泛型时
List arrayList = new ArrayList();
arrayList.add("aaaa");
arrayList.add(100);
for(int i = 0; i< arrayList.size();i++){
String item = (String)arrayList.get(i);
Log.d("泛型测试","item = " + item);
}
在运行时会出现java.lang.ClassCastException
类型转换异常,引入泛型后,
- 代码更加简洁【不用强制转换】
- 程序更加健壮【只要编译时期没有警告,那么运行时期就不会出现ClassCastException异常】
- 可读性和稳定性【在编写集合的时候,就限定了类型】
3. 使用
泛型类,泛型接口,泛型方法
4.通配符
例子
public void showKeyValue1(Generic<Number> obj){
Log.d("泛型测试","key value is " + obj.getKey());
}
Generic<Integer> gInteger = new Generic<Integer>(123);
Generic<Number> gNumber = new Generic<Number>(456);
showKeyValue(gNumber);
// showKeyValue这个方法编译器会为我们报错:Generic<java.lang.Integer>
// cannot be applied to Generic<java.lang.Number>
// showKeyValue(gInteger);
通过提示信息我们可以看到Generic<Integer>
不能被看作为Generic<Number>
的子类。由此可以看出:同一种泛型可以对应多个版本(因为参数类型是不确定的),不同版本的泛型类实例是不兼容的。
回到上面的例子,如何解决上面的问题?总不能为了定义一个新的方法来处理Generic<Integer>
类型的类,这显然与java中的多台理念相违背。因此我们需要一个在逻辑上可以表示同时是Generic<Integer>
和Generic<Number>
父类的引用类型。由此类型通配符应运而生。
?号通配符表示可以匹配任意类型,任意的Java类都可以匹配
通配符上下限
list<? extends Number>
list集合装载的只能是Number类型或者其子类,上限
public static void main(String[] args) {
//List集合装载的是Integer,可以调用该方法
List<Integer> integer = new ArrayList<>();
test(integer);
//List集合装载的是String,在编译时期就报错了
List<String> strings = new ArrayList<>();
test(strings);
}
public static void test(List<? extends Number> list) {
}
<? super Type>
//传递进来的只能是Type或Type的父类
泛型擦除
泛型是提供给javac编译器使用的,它用于限定集合的输入类型,让编译器在源代码级别上,即挡住向集合中插入非法数据。但编译器编译完带有泛型的java程序后,生成的class文件中将不再带有泛形信息,以此使程序运行效率不受到影响,这个过程称之为“擦除”。
参考:
https://www.cnblogs.com/coprince/p/8603492.html
https://segmentfault.com/a/1190000014120746