一直對java泛型一知半解,決定好好理解一下泛型.
泛型的基本使用:
我們最常用到泛型的地方可能是arraylist中,如:ArrayList<Integer> intList = new ArrayList<Integer>();它可以構(gòu)造各種類型的變量來組裝成不同的list而不必對每一個類型都創(chuàng)建一個Arraylist的類,
- 定義及使用:
//定義
class Person<T>{// 此處可以隨便寫標(biāo)識符號
private T x ;
private T y ;
public void setAge(T x){//作為參數(shù)
this.x = x ;
}
public void setName(T y){
this.y = y ;
}
public T getAge(){//作為返回值
return this.x ;
}
public T getName(){
return this.y ;
}
};
因為T表示派生自O(shè)bject類的任何類,所以尖括號T中必須是繼承自O(shè)bject,如:String,Interger,不能使用原始的類型,如int,double.
//使用
//設(shè)置年齡
Person<Integer> p = new Person<Integer>() ;
p.setAge(new Integer(100)) ;
System.out.println(p.getAge());
//設(shè)置名字
Person<String> p = new Person<String>() ;
p.setName(new String("name")) ;
System.out.println(p.getName());
使用的Class<T> object來傳遞類的class對象
我們在解析Json的時候:
public static List<SuccessModel> parseSuccessArray(String response){
List<SuccessModel> modelList = JSON.parseArray(response, SuccessModel.class);
return modelList;
}
這樣做比較的死板,我們可以吧successmodel抽取出來,當(dāng)做一個變量,這樣就可以使用到泛型了,如下:
public static <T> List<T> parseArray(String response,Class<T> object){
List<T> modelList = JSON.parseArray(response, object);
return modelList;
}
注意到,我們用的Class<T> object來傳遞類的class對象,即我們上面提到的SuccessModel.class,這樣就可以傳遞任意的class來解析不同的數(shù)據(jù).
//待續(xù)。。。。
進階
類型綁定:
有時候定義泛型的時候可能希望泛型類型只能是一部分類型,就是給泛型指定一個界限,
定義形式為:
<T extends BoundingType>
T和BoundingType可以是類,也可以是接口。另外注意的是,此處的”extends“表示的子類型,不等同于繼承。在這里extends后的BoundingType可以是類,也可以是接口.
通配符:
通配符用?表示無邊界通配符,通配符的意義就是他是一個未知的符號,可以表示任意的類,如:
Point<?> point;
point = new Point<Integer>(3,3);
point = new Point<Float>(4.3f,4.3f);
point = new Point<Double>(4.3d,4.90d);
point = new Point<Long>(12l,23l);
- 通配符?和T的區(qū)別:
泛型變量T不能在代碼用于創(chuàng)建變量,只能在類,接口,函數(shù)中聲明以后,才能使用。
而無邊界通配符?則只能用于填充泛型變量T,表示通配任何類型
如:
Box<?> box;
box = new Box<String>();
?只能出現(xiàn)在Box<?> box;中,其它位置都是不對的
- 通配符?的extends綁定:
通配符可以和泛型一樣加以限定。如:
Point<? extends Number> point;
注意:利用<? extends Number>定義的變量,只可取其中的值,不可修改
如:
Point<? extends Number> point = new Point<Integer>(3);
point的類型是由Point<? extends Number>決定的,并不會因為point = new Point<Integer>(3);而改變類型。如果會改變類型那么<? extends Number>就失去了作用。但取值時,正由于泛型變量T被填充為<? extends Number>,所以編譯器能確定的是T肯定是Number的子類,編譯器就會用Number來填充T。
通配符?的super綁定:
如果說 <? extends XXX>指填充為派生于XXX的任意子類的話,那么<? super XXX>則表示填充為任意XXX的父類.
如:
class CEO extends Manager {
}
class Manager extends Employee {
}
class Employee {
}
List<? super Manager> list;
list = new ArrayList<Employee >();
list = new ArrayList<Manager >();
list = new ArrayList<CEO >();//編譯會報錯
因為CEO類已經(jīng)不再是Manager的父類了。所以會報編譯錯誤。
注意:super通配符表示的實例內(nèi)容:能存不能取
先看存的部分:
List<? super Manager> list;
list = new ArrayList<Employee>();
//存
list.add(new Employee()); //編譯錯誤
list.add(new Manager());
list.add(new CEO());
為什么會報編譯錯誤呢?因為
編譯器無法確定<? super Manager>的具體類型,但唯一可以確定的是Manager()、CEO()肯定是<? super Manager>的子類,所以肯定是可以add進去的。但Employee不一定是<? super Manager>的子類,所以不能確定,不能確定的,肯定是不允許的,所以會報編譯錯誤。
super和extends相反,使用super關(guān)鍵字時,往里存的只要是Employee的子類,就會強制轉(zhuǎn)換為Employee存儲,但是取出來時應(yīng)該都為父類Employee所以沒有意義,所以我們認為super通配符:能存不能??;
總結(jié)
extends 和 the ? super 通配符的特征,我們可以得出以下結(jié)論:
◆ 如果你想從一個數(shù)據(jù)類型里獲取數(shù)據(jù),使用 ? extends 通配符(能取不能存)
◆ 如果你想把對象寫入一個數(shù)據(jù)結(jié)構(gòu)里,使用 ? super 通配符(能存不能?。?br>
◆ 如果你既想存,又想取,那就別用通配符。