泛型概念
泛型: Generic Programming:编写的代码可以被很多不同类型的对象使用。
泛型类:ArrayList, HashSet, HashMap等。
泛型方法:Collections.binarySearch, Arrays.sort等。
泛型接口:List, Iterator等。
泛型的本质:参数化类型,避免类型的转化,代码可以重复使用。
自定义泛型设计
- 泛型类:具有泛型变量的类,在类名后用< T>代替引入类型,直到创建对象的时候,确定具体的类型。
泛型类的定义:
整个类都被泛化,包括变量和方法。
public class Interval<T>{
private T upper;
private T lower;
public Interval(T upper, T lower){
this.upper = upper;
this.lower = lower;
}
public T getLower(){
return lower;
}
public T getUpper(){
return upper;
}
}
泛型类调用:
传入具体的类和参数。
public static void main(String[] args){
Interval<Integer> v1 = new Interval<>(1, 2);
int lower = v1.getLower();
int upper = v1.getUpper();
System,out.println(lower + ", " + upper);
Interval<Integer> v2 = new Integer<>(2, 3);
Interval<Integer> v3 = getReverse(v2);
System.out.println(v3.getLower() + ", " + v3.getUpper());
}
//该方法为泛型方法:方法被泛化,包括返回值和参数。
//第一个<T>为规定了后面的类型均为T,Interval<T> 为返回值类型。
public static <T> Interval<T> GetReverse(Interval<T> interval){
return new Interval<T>(interval.getLower(), interval.getUpper());
}
- 泛型接口:T 可以再是一个泛型类。
public class Interval<T>{
private T lower;
private T upper;
public Interval(T lower, T upper){
this.lower = lower;
this.upper = upper;
}
public T getLower(){
return lower;
}
public T getUpper(){
return upper;
}
}
public interface Caculator<T>{
public T add(T o1, T o2);
}
public class IntervalCaculator implements Caculator<Interval<Integer>>{
public static void main(String[] args){
Caculator<Interval<Integer>> c = new IntervalCaculator();
Interval<Integer> o1 = new Interval<>(1, 2);
Interval<Integer> o2 = new Interval<>(2, 3);
Interval<Integer> o3 = c.add(o1, o2);
System.out.println(o3.getLower() + ", " + o3.getUpper());
}
public Interval<Integer> add(Interval<Integer> o1, Interval<Integer> o2){
int lower = o1.getLower() + o2.getLower();
int upper = o1.getUpper() + o2.getUpper();
return new Interval<Integer>(lower, upper);
}
}
范型类型限定
泛型限定
-
T 必须是Comparable的子类。extends是固定的,后面可以有多个,用 & 来拼接。
extends限定可以限定多个接口,但是只能是一个类。且类必须在开头。
使用逗号分隔参数,<T extends File & Cloneable, U extends Serializable>。 -
泛型的继承原则:Pair 和Pair< S> 没有任何关系,即使T和S存在关系。
泛型通配符
-
上限界定符:Pair<? extends S>。
Pair能接收的参数类型:S本身及其子类。
如果有Apple类和Orange类均继承于Fruit类。
则:
Pair<? extends Fruit> 代表Pair< Fruit>, Pair< Apple>, Pair< Orange>。
(子类型可以转为父类型)。
只能get,不能set,只能确定get得到的类型一定可以转型为Fruit类型。不可保证放进去的是什么类型。 -
下限界定符:Pair<? supper S>。
Pair能够接收的类型,S本身及其超类。
如果有:
GreenApple继承于Apple,
Apple继承于Fruit,
Fruit继承于Object。
则:
Pair<? supper Apple>可表示:Pair< Object>, Pair< Fruit>, Pair< Apple>。
Pair<? supper Apple> fruits = new Pair<Fruit>();
//可以,因为Fruit类在 ?supper Apple内。
fruits.setFirst(new Apple(3));//Apple可以转型为Fruit类
fruits.setSecond(new GreenApple(2));//GreenApple可以转型为Fruit。
fruits.setSecond(new Object());//出问题,Object不可以向下转型为Fruit。
注意,下限界定符:只能set,不可get。可以放进去Apple及其子类。
泛型PECS原则:
(Productor Extends Consumer Supper)
要从泛型类中读数据不写入,使用? extends S;要写数据不读,使用 ? supper S。既要读又要写,不使用通配符。
范型的本质和约束
泛型是JDK1.5引入的新特性。JDK版本是向后兼容的。
JVM里面没有泛型对象,而是在编译采用类型擦除技术,将泛型转为限定类型。
- 擦除泛型变量,替换为原始类型,无限定类型时为Object。
public class Pair<T>{
private T first;
private T second;
public Pair(T first, T second){
this.first = first;
this.second = second;
}
public T getFirst(){
return first;
}
public void setFirst(T first){
this.first = first;
}
}
转为:
public class Pair<Object>{
private Object first;
private Object second;
public Pair(Object first, Object second){
this.first = first;
this.second = second;
}
public Object getFirst(){
return first;
}
public void setFirst(Object first){
this.first = first;
}
}
-
擦除泛型变量,替换为原始类型,有限定为第一个类型。
-
重载泛型方法翻译:采用自动桥的方法;使得子类重载父类方法后,调用时,还是调用子类的方法。
java 类型的协变和逆变
类型变化关系(Type Variance):
A, B 是两个类型,f(*)表示类型转换,<=表示继承,如A<=B,表示A继承于B。
- java 数组是协变的。
如:String 是Object的子类,则,String[] 也是Object[]的子类。 - Java泛型是不变的。
如:String是Object的子类,但是List和List没有关系。
但是,泛型可采用通配符,支持协变和逆变(PECS原则)。