一直對(duì)java泛型一知半解,決定好好理解一下泛型.
泛型的基本使用:
我們最常用到泛型的地方可能是arraylist中官扣,如:ArrayList<Integer> intList = new ArrayList<Integer>();
它可以構(gòu)造各種類(lèi)型的變量來(lái)組裝成不同的list而不必對(duì)每一個(gè)類(lèi)型都創(chuàng)建一個(gè)Arraylist的類(lèi),
- 定義及使用:
//定義
class Person<T>{// 此處可以隨便寫(xiě)標(biāo)識(shí)符號(hà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 ;
}
};
因?yàn)門(mén)表示派生自O(shè)bject類(lèi)的任何類(lèi),所以尖括號(hào)T中必須是繼承自O(shè)bject,如:String,Interger,不能使用原始的類(lèi)型,如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來(lái)傳遞類(lèi)的class對(duì)象
我們?cè)诮馕鯦son的時(shí)候:
public static List<SuccessModel> parseSuccessArray(String response){
List<SuccessModel> modelList = JSON.parseArray(response, SuccessModel.class);
return modelList;
}
這樣做比較的死板芙委,我們可以吧successmodel抽取出來(lái)逞敷,當(dāng)做一個(gè)變量,這樣就可以使用到泛型了灌侣,如下:
public static <T> List<T> parseArray(String response,Class<T> object){
List<T> modelList = JSON.parseArray(response, object);
return modelList;
}
注意到推捐,我們用的Class<T> object來(lái)傳遞類(lèi)的class對(duì)象,即我們上面提到的SuccessModel.class侧啼,這樣就可以傳遞任意的class來(lái)解析不同的數(shù)據(jù).
//待續(xù)牛柒。。痊乾。皮壁。
進(jìn)階
類(lèi)型綁定:
有時(shí)候定義泛型的時(shí)候可能希望泛型類(lèi)型只能是一部分類(lèi)型,就是給泛型指定一個(gè)界限,
定義形式為:
<T extends BoundingType>
T和BoundingType可以是類(lèi)哪审,也可以是接口闪彼。另外注意的是,此處的”extends“表示的子類(lèi)型协饲,不等同于繼承。在這里extends后的BoundingType可以是類(lèi)缴川,也可以是接口.
通配符:
通配符用?表示無(wú)邊界通配符茉稠,通配符的意義就是他是一個(gè)未知的符號(hào),可以表示任意的類(lèi)把夸,如:
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)建變量而线,只能在類(lèi),接口恋日,函數(shù)中聲明以后膀篮,才能使用。
而無(wú)邊界通配符岂膳?則只能用于填充泛型變量T誓竿,表示通配任何類(lèi)型
如:
Box<?> box;
box = new Box<String>();
?只能出現(xiàn)在Box<?> box;中谈截,其它位置都是不對(duì)的
- 通配符?的extends綁定:
通配符可以和泛型一樣加以限定筷屡。如:
Point<? extends Number> point;
注意:利用<? extends Number>定義的變量,只可取其中的值簸喂,不可修改
如:
Point<? extends Number> point = new Point<Integer>(3);
point的類(lèi)型是由Point<? extends Number>決定的,并不會(huì)因?yàn)閜oint = new Point<Integer>(3);而改變類(lèi)型毙死。如果會(huì)改變類(lèi)型那么<? extends Number>就失去了作用。但取值時(shí)喻鳄,正由于泛型變量T被填充為<? extends Number>扼倘,所以編譯器能確定的是T肯定是Number的子類(lèi),編譯器就會(huì)用Number來(lái)填充T除呵。
通配符再菊?的super綁定:
如果說(shuō) <? extends XXX>指填充為派生于XXX的任意子類(lèi)的話(huà)爪喘,那么<? super XXX>則表示填充為任意XXX的父類(lèi).
如:
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 >();//編譯會(huì)報(bào)錯(cuò)
因?yàn)镃EO類(lèi)已經(jīng)不再是Manager的父類(lèi)了。所以會(huì)報(bào)編譯錯(cuò)誤袄简。
注意:super通配符表示的實(shí)例內(nèi)容:能存不能取
先看存的部分:
List<? super Manager> list;
list = new ArrayList<Employee>();
//存
list.add(new Employee()); //編譯錯(cuò)誤
list.add(new Manager());
list.add(new CEO());
為什么會(huì)報(bào)編譯錯(cuò)誤呢?因?yàn)?br>
編譯器無(wú)法確定<? super Manager>的具體類(lèi)型腥放,但唯一可以確定的是Manager()、CEO()肯定是<? super Manager>的子類(lèi)绿语,所以肯定是可以add進(jìn)去的秃症。但Employee不一定是<? super Manager>的子類(lèi),所以不能確定吕粹,不能確定的种柑,肯定是不允許的,所以會(huì)報(bào)編譯錯(cuò)誤匹耕。
super和extends相反聚请,使用super關(guān)鍵字時(shí),往里存的只要是Employee的子類(lèi),就會(huì)強(qiáng)制轉(zhuǎn)換為Employee存儲(chǔ),但是取出來(lái)時(shí)應(yīng)該都為父類(lèi)Employee所以沒(méi)有意義稳其,所以我們認(rèn)為super通配符:能存不能仁簧汀;
總結(jié)
extends 和 the ? super 通配符的特征既鞠,我們可以得出以下結(jié)論:
◆ 如果你想從一個(gè)數(shù)據(jù)類(lèi)型里獲取數(shù)據(jù)煤傍,使用 ? extends 通配符(能取不能存)
◆ 如果你想把對(duì)象寫(xiě)入一個(gè)數(shù)據(jù)結(jié)構(gòu)里,使用 ? super 通配符(能存不能戎龅啊)
◆ 如果你既想存蚯姆,又想取,那就別用通配符洒敏。
參考鏈接:
夯實(shí)JAVA基本之一 —— 泛型詳解(1):基本使用
夯實(shí)JAVA基本之一——泛型詳解(2):高級(jí)進(jìn)階