一幸斥、簡(jiǎn)述
jdk5以前弧满,對(duì)象保存到集合中就會(huì)失去其特性勋篓,取出時(shí)通常要程序員手工進(jìn)行類型的強(qiáng)制轉(zhuǎn)換吧享,這樣不可避免就會(huì)引發(fā)程序的一些安全性問題。jdk5中的泛型允許程序員在編寫集合代碼時(shí)譬嚣,就限制集合的處理類型钢颂,從而把原來程序運(yùn)行時(shí)可能發(fā)生問題,轉(zhuǎn)變?yōu)榫幾g時(shí)的問題孤荣,以此提高程序的可讀性和穩(wěn)定性甸陌。使用泛型時(shí)须揣,泛型類型必須為引用類型盐股,不能是基本數(shù)據(jù)類型。
注意:泛型是提供給javac編譯器使用的耻卡,它用于限定集合的輸入類型疯汁,讓編譯器在源代碼級(jí)別上,就擋住向集合中插入非法數(shù)據(jù)卵酪。但編譯器編譯完帶有泛型的Java程序后幌蚊,生成的class文件中將不再帶有泛型信息,以此使程序運(yùn)行效率不受到影響溃卡,這個(gè)過程稱之為“擦除”溢豆。
二、泛型的基本術(shù)語
以ArrayList<E>為例:<>念typeof
- ArrayList<E>中的E稱為類型參數(shù)變量
- ArrayList<Integer>中的Integer稱為實(shí)際類型參數(shù)
- 整個(gè)ArrayList<E>稱為泛型類型
- 整個(gè)ArrayList<Integer>稱為參數(shù)化的類型(ParameterizedType)
用泛型時(shí)瘸羡,如果兩邊都使用到泛型時(shí)漩仙,兩邊的泛型必須要一樣。 只用一邊也可以犹赖。如:
三队他、通配符T,E峻村,K麸折,V
定義泛型接口、泛型類粘昨、泛型方法的時(shí)候經(jīng)常會(huì)碰見不同的通配符T垢啼,E窜锯,K,V等等芭析,這些通配符表示什么意思呢衬浑?
這幾個(gè)其實(shí)沒什么區(qū)別,只不過是一個(gè)約定好的代碼放刨,也就是說使用大寫字母A工秩、B、C进统、D......X助币、Y、Z定義的螟碎,就都是泛型眉菱,把T換成A也一樣,這里T只是名字上的意義而已掉分。將T換成了A俭缓,在執(zhí)行效果上是沒有任何區(qū)別的,只不過約定好了T代表type酥郭,所以按照規(guī)范來增加了代碼的可讀性华坦。如果要定義三個(gè)或三個(gè)以上的泛型參數(shù)可以使用T1, T2, ..., Tn。
- 不从? 表示不確定的Java類型
- T (type) 表示具體的一個(gè)Java類型
- K V (key value) 分別代表Java鍵值中的Key Value
- E (element) 代表Element
四惜姐、List<T>,List<Object>椿息,List<?>區(qū)別
- ArrayList<T> al=new ArrayList<T>(); 指定集合元素只能是T類型
- ArrayList<?> al=new ArrayList<?>(); 集合元素可以是任意類型歹袁。這種沒有意義,一般是方法中寝优,只是為了說明用法
- ArrayList<? extends E> al=new ArrayList<? extends E>();
泛型的限定:
? extends E:接收E類型或者E的子類型条舔。
? super E:接收E類型或者E的父類型
注意:
- Object和T不同點(diǎn)在于,Object是一個(gè)實(shí)打?qū)嵉念惙Ψ]有泛指誰孟抗,而 T 可以泛指Object。
比如public void printList(List<T> list){}
方法中可以傳入List<Object> list類型參數(shù)妻熊,也可以傳入List<String> list類型參數(shù)夸浅,但是public void printList(List<Object> list){}
就只允許傳入List<Object> list類型參數(shù),因?yàn)镺bject類型并沒有泛指誰扔役,是一個(gè)確定的類型帆喇。 - ?和T區(qū)別:? 是一個(gè)不確定類,? 和T都表示不確定的類型亿胸。但如果是T的話坯钦,函數(shù)里面可以對(duì)T進(jìn)行操作预皇,比方 T zoo = getZoo(),而不能用? zoo = getZoo()婉刀。
五吟温、T,Class<T>突颊,Class<?>區(qū)別
1??T是一種具體的類鲁豪。例如String,List律秃,Map......等等爬橡,這些都是屬于具體的類。
2??Class也是一個(gè)類棒动,但Class是存放上面String糙申,List,Map......類信息的一個(gè)類船惨,有點(diǎn)抽象柜裸。
3??Class<T>在實(shí)例化的時(shí)候,T要替換成具體類粱锐;
4??Class<?>它是個(gè)通配泛型疙挺,?可以代表任何類型,主要用于聲明時(shí)的限制情況卜范。
例如可以聲明一個(gè):
public Class<?> clazz;
而以下的聲明卻不可以衔统,因?yàn)門需要指定類型:
public Class<T> clazz;
所以當(dāng)不知道聲明什么類型的Class的時(shí)候可以定義一個(gè)Class<?>鹿榜。Class<?>可以用于參數(shù)類型定義海雪,方法返回值定義等。
六舱殿、Class<T>和Class<?>適用于什么時(shí)候呢奥裸?
使用Class<T>和Class<?>多發(fā)生在反射場(chǎng)景下。如果不使用泛型沪袭,反射創(chuàng)建一個(gè)類如下:
Teacher t = (Teacher) Class.forName("com.xxp.Teacher").newInstance();
需要強(qiáng)轉(zhuǎn)湾宙,如果反射的類型不是Teacher類,就會(huì)報(bào)java.lang.ClassCastException錯(cuò)誤冈绊。但是使用Class<T>泛型后侠鳄,不用強(qiáng)轉(zhuǎn)了。
七死宣、獲取到Class類的三種方式
1??調(diào)用 Object 類的 getClass()方法來得到Class對(duì)象伟恶,這是最常見的產(chǎn)生Class對(duì)象的方法。例如:
List list = null;
Class clazz = list.getClass();
2??使用Class類的中靜態(tài)forName()方法獲得與字符串對(duì)應(yīng)的Class對(duì)象毅该。例如:
Class clazz = Class.forName("com.xxp.Teacher");
3??如果T是一個(gè)Java類型博秫,那么T.class就代表了匹配的類對(duì)象潦牛。
Class clazz = List.class;