Java泛型

来源:互联网 发布:苹果网络锁破解 编辑:程序博客网 时间:2024/05/21 06:28
泛型的概念
泛型指的是:声明中具有一个或者多个类型参数的类或者接口,称为泛型。
泛型的好处:引入泛型带来两个好处 安全性和表述性。
安全性指的是,从集合中删除元素时不需要再进行手工的强制转换。编译器会替你插入隐式的转换。这个可以通过javap查看类的字节码文件看到。
checkcase 检测类型转换
表述性指的是:通过声明一个参数化的类型,List<String> strList; 错误的插入在编译期间就会被告知,相当于编译器会检测往strlist里插入的元素是否是String类型,不是则会在编译时报错。

两个概念 1. code specialization 2.code sharing
指的是在jdk底层对于泛型类的字节码是共享的还是单独的。jdk对于泛型类和接口的字节码是共享的
泛型擦除:只有在编译器对容器的类型进行编译,编译后就把类型擦除。
或者也可以这么说 通过类型参数的合并,将泛型类型的实例关联到同一份字节码上

泛型的术语
ArratList<E>:泛型类型
ArrayList<E> 中的E 称为类型变量或者类型参数
ArratList<Integer>:参数化的泛型类型
ArratList<Integer>中的Integer 称为类型参数的实例或者实际类型参数
ArratList<Integer>中的<> 念做 typeof
ArratList 称为泛型的原始类型

泛型的使用
泛型类 或 接口
interface A<T>{}
class B<T> {}
即在类名后面加上<T> 然后在成员域或 非静态方法的参数列表中都可以使用

泛型类:
泛型类可以独立存在,即泛型方法可以在泛型类中 也可以在非泛型类中存在
public <T> void method(T t)
即在返回类型前加上<T>

泛型的边界
泛型边界指的是可以在泛型类的参数类型上添加限制条件。复用了extends关键字。
作用是 1,强制规定了泛型可以应用的类型
2,可以按照边界类型来调用方法

比如 interface A{
Void methodA();
}

Class B<T extends A>{
T t;
void methodA(T t){
t.methodA();
}
}
原理就是因为泛型经过擦除后 methodA 其实入参数是 A ,所以可以调用 接口的方法。
泛型的擦除
泛型的擦除指的是泛型类在经过编译器编译后,类型参数会被擦除,擦除到它的第一个边界(它可能存在多个边界)
为什么会有泛型擦除,这是因为泛型并不是从jdk1.0开始的,泛型的出现还要兼容之前非泛型的代码。
第二,泛型类的字节码只有一份,不同的泛型实例最终会映射到一份字节码上,(这也是必须的,如果一个实例一份字节码 那估计字节码就撑爆了)

擦除到第一个边界:A,B是两个接口
public classE<TextendsA & B> {

Titem;
public voidmethod(Tt){
t.methodA();
t.methodB();
}
}
擦除到第一个边界是什么意思呢 首先,可能疑惑的是这个类编译后method()的数字签名是什么,有一种个类 既实现了A 又实现了B么,不一定吧 那编译器怎么处理呢?我们看看他的字节码
public void method(T);
Signature: (Lgeneric/test/A;)V
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: aload_1
1: invokeinterface #2, 1 // InterfaceMethod generic/test/A.
methodA:()V
6: aload_1
7: checkcast #3 // class generic/test/B
10: invokeinterface #4, 1 // InterfaceMethod generic/test/B.
methodB:()V
15: return
字节码的结果显示method的数字签名是(Lgeneric/test/A;)V,那么你会疑惑,那为什么t能调用methodB()方法呢, 看看7:checkcast 原来编译器在这边隐式的给我们加了强制类型转换,多个边界的时候,泛型擦除只会擦除到第一个边界,但是在编译的时候,编译器会加上类型转换

泛型的通配符
Java编程思想:泛型的通配符出现的原因是为了解决泛型类不协变。即有时候我们希望在两个泛型类之间建立某种向上转型的关系
Effective in Java:如果要使用泛型,但又不确定或者不在乎实际的类型参数,可以使用一个问号代替。

我自己总结把通配符分为两类:有上界的通配符<? extends ..> 和 有下界的通配符<? super..>
(其中把无边界的通配符归到了上第一种 List<?> 相当于 List<? extends Object>)

分析一下这两种有界通配符的用法
//是Object的子类
public static void printCollection(Collection<? extends Object> colleciton){
//colleciton.add(new Object()); //除了null 都不能添加
for(Object o : collection) System.out.println(o);
}
//是Fruit的父类
public static void printCollection(Collection<? super Fruit> colleciton){
colleciton.add(new Fruit()); //可以添加Fruit的子类
for(Object o : collection) System.out.println(o);
}

总结 使用?通配符可以引用其他各种参数化的类型(List<?> list = new ArrayList<String>();),
?通配符定义的变量(?)的主要作用是引用,可以调用与参数化无法的方法,不能调用与参数化有关的方法

0 0