[size=large]一.泛型的好处:[/size]
理解Java泛型最简单的方法是把它看成一种便捷语法,节省类型转换的代码
[size=large]二.协变:[/size]
在数组中协变是支持的,Apple[]可以复制给Fruit[].但是在泛型中是不支持协变的,List<Apple>是不能复制给List<Fruit>,例如:
[color=red]解决办法:[/color]
[size=large]三.擦除:[/size]
泛型其实只是在编译器中实现的而虚拟机并不认识泛型类项,所以要在虚拟机中将泛型类型进行擦除。也就是说,在编译阶段使用泛型,运行阶段取消泛型,即擦除。
1.在java中编译器只生成唯一的一份目标代码List类,该泛型类的所有实例都映射到这份目标代码上,在需要的时候执行类型检查和类型转换。
2.在实例化一个泛型类或泛型方法时都产生一份新的目标代码,针对Integer,String类型的两个List类
擦除带来的问题:
[color=darkred]解决办法:[/color]
[size=large]四.限制泛型中类型参数的范围:[/size]
总结 ? extends 和 the ? super 通配符的特征,我们可以得出以下结论:
•如果你想从一个数据类型里获取数据,使用 ? extends 通配符
•如果你想把对象写入一个数据结构里,使用 ? super 通配符
•如果你既想存,又想取,那就别用通配符。
理解Java泛型最简单的方法是把它看成一种便捷语法,节省类型转换的代码
[size=large]二.协变:[/size]
在数组中协变是支持的,Apple[]可以复制给Fruit[].但是在泛型中是不支持协变的,List<Apple>是不能复制给List<Fruit>,例如:
take(List<Fruit> fruits){}//只有真正的List<Fruit>才能调用take(..),Fruit的子类是无法调用的
[color=red]解决办法:[/color]
take(List<? extends Fruit> fruits){
fruits.add(new Apple());//编译出错,只能进行读,不能进行写操作,因为List内的具体类型是不确定的
}//Fruit的子类是都可以调用
[size=large]三.擦除:[/size]
泛型其实只是在编译器中实现的而虚拟机并不认识泛型类项,所以要在虚拟机中将泛型类型进行擦除。也就是说,在编译阶段使用泛型,运行阶段取消泛型,即擦除。
List<Integer>,List<String>
1.在java中编译器只生成唯一的一份目标代码List类,该泛型类的所有实例都映射到这份目标代码上,在需要的时候执行类型检查和类型转换。
2.在实例化一个泛型类或泛型方法时都产生一份新的目标代码,针对Integer,String类型的两个List类
擦除带来的问题:
public class Erased<T>{
private T[] arr;
public Erased(){
T t = new T();//illegal因为在编译的时候不知道构造哪个具体的类
arr = new T[1];//illegal
arr = (T[])new Object[1];//Unchecked warning
}
public void doSomething(Set<?> set){
Set<?> copy = new HashSet<?>(set);//illegal
Set<?> copy2 = new HashSet<Object>(set);//合法
}
}
[color=darkred]解决办法:[/color]
public class Erased<T>{
private T[] arr;
private Class<T> type;
public Erased(Class<T> type){
this.type = type;
Class<T>[] arrs = new Class[1];//方法一
arr = (T[])arrs;
//arr = (T[])Array.newInstance(type,1);//方法二
}
}
[size=large]四.限制泛型中类型参数的范围:[/size]
<K extends String>和<V super Integer>
不是表示继承和超类,而是表示类型的范围,表示K<=Sting,V>=Integer
class C<T extends Comparable<? super T> & Serializable>
我们来分析以下这句,T extends Comparable这个是对上限的限制,Comparable<? super T>这个是下限的限制,Serializable是第2个上限。一个指定的类型参数可以具有一个或多个上限。具有多重限制的类型参数可以用于访问它的每个限制的方法和域。
总结 ? extends 和 the ? super 通配符的特征,我们可以得出以下结论:
•如果你想从一个数据类型里获取数据,使用 ? extends 通配符
•如果你想把对象写入一个数据结构里,使用 ? super 通配符
•如果你既想存,又想取,那就别用通配符。