首先看一看java泛型类的使用:
/*** 一个泛型方法:使程序更加安全
* 并且能被更多的使用
*@author丁**
*
*@param*/
class Pair{privateT first;privateT second;//实例化类型变量
public static Pair makePair(Classcl){try{return new Pair<>(cl.newInstance(), cl.newInstance());
}catch(Exception e) {return null;
}
}public Pair(){ first = null; second = null; }public Pair(T first, T second){ this.first = first; this.second =second;}publicT getFirst() {returnfirst;
}public voidsetFirst(T first) {this.first =first;
}publicT getSecond() {returnsecond;
}public voidsetSecond(T second) {this.second =second;
}
}
classFather {private int age = 40;public voidgetName(){
System.out.println(age);
}
}class Son extendsFather{private int age = 12;public voidgetName() {
System.out.println(age);
}
}
在普通类中:Father aa = new Son();父类是可以用来指向子类的
但是在泛型类中却不是如此:
Pair bb = new Pair<>();
Pair cc = bb;//error
1:虽然Son是Father的子类,但是Pair之间没有继承关系:
List a1 = new ArrayList<>();
List a2 = new ArrayList<>();//设a1可以等于a2//a1 = a2;//a1.add(1111);因为是对a1进行操作,所以可以添加Object,a1.add(Object ad);//a2.get(0);报错,因为a1添加Object进入了a2的空间中,但是a2是String类型,所以报错
2:可以将参数化类型转换成一个原始类型:
List a2 = new ArrayList<>();
List a3= a2;//可以通过编译,但是后面使用方法时可能会产生类型错误!//这时候a3对象时原始类型,所以add(Object obj);
a3.add(123);//是对a3进行操作,但是最终结果保存到了a2中,将一个Integer装入String中
显然是错误的;
3:泛型类可以扩展或实现其他的泛型类:
//泛型接口
interface List1{
}//实现了泛型接口的泛型类
class List2 implements List1{
}//泛型类
class List3{
}//继承了其他泛型类的泛型类
class List4 extends List3{
}
List1 b1 = new List2();//因为List2实现了List1
List3 b2 = new List4();//List4继承了List3,所以List3是父类,可以指向子类对象。
虽然这样也完成了泛型类的继承,实现了和普通类一样的多态,但是使用起来并不是特别好,就这样java引入了通配符概念:
通配符上限:
/*通配符的上限:Pair extends Father> c2
extends是关键字
Pair代表的是某个唯一(具体的泛型类)的泛型类:比如Pair,Pair
但是Pair extends Father>不是具体的泛型类,它所指的是参数类型为Father的子类的所有泛型类(包括Father)*/Pair extends Father>c3;
Pair c1 = new Pair<>();
Pair c2 = new Pair<>();//c2 = c1;error
c3 =c1;
c3= c2;
需要注意的是:
/** 使用通配符的上限的问题:
* ? extends Father getFirst();
* void setFirst(? extends Father);
* 当c2= c1时:
* c2.setFirst(Father father);时,会将Father对象添加到Son对象内存中,这是不好的
* 所以使用extends上限时,不能使用setFirst(? extends Father),add(? extends Father)* 等方法。
* 但可以使用getFirst();方法*/
c2.setFirst( new Father(); );//error
通配符下限:
/** 通配符的下限:
* ? super Son
* 表示的不是某个具体的泛型类,而是表示参数类型为Son的父类的所有可能的泛型类(包括* * Son)
* 和通配符上限一样,通配符的超类型限定不能使用getFirst()方法,但可以使用setFirst(XX)方法*/Pair c1 = new Pair<>();
Pair super Son>c3;
c3= c1;
//另一种超类型限定的写法
Pair> c4;
无限定通配符:
//无限定通配符
Pair c7 = new Pair<>();
Pair c5 = new Pair<>();//c7 = c5;error,因为他们不是同一种类型
Pair> c6 = new Pair<>();
c6= c5;//Pair>是所有的Pair泛型类的父类,Pair> c6 = new Pair();
Pair>和Pair的本质不同在于:可以用任意的Object对象调用原始的Pair类的setObject()方法;
通配符的捕获:
//交换First,Second变量值
public static void swap(Pair>p){? t = p.getFirst();//error,因为通配符(?)不是类型变量,所以不能直接将?写入代码中,利用通配符的捕获来解决这个问题。
p.setFirst(p.getSecond());
p.setSecond(t);
}
//交换First,Second变量值
public static void swap(Pair>p){
swapHelper(p);//在调用下面的方法时,类型参数就被捕获了。
}//利用通配符的捕获来解决该问题
public static void swapHelper(Pairp){
T t= p.getFirst();//T是具体的某个类型。
p.setFirst(p.getSecond());
p.setSecond(t);
}
注意:通配符的捕获只有在许多限制的情况下才是合法的,编译器必须能够确信通配符表达的是单个,确定的类型。