在JavaSE 1.5中,Java引入泛型的概念恢总。那么何為泛型呢迎罗?
泛型就是將類型參數(shù)化,也就是說將所操作的數(shù)據(jù)類型指定為一個參數(shù)片仿,從而使代碼可以復用纹安,并且引入泛型意味著更好的類型安全。
泛型可以被使用到類砂豌、接口和方法中厢岂。
泛型的使用在集合中尤為突出。
一阳距、定義&使用
在定義泛型類咪笑、泛型接口或泛型方法使,在<>
中指定一個或多個類型參數(shù)的名字娄涩。對于類型參數(shù)的名字可以使用任何Java標識符(由字符窗怒、數(shù)字映跟、下劃線(_)、美元符($)組成扬虚,不能以數(shù)字開頭)努隙,但為了規(guī)范化和達到見名知意的目的,建議使用簡練的名字辜昵,多使用單個字符荸镊,并且最好避免小寫字母。
在這里建議大家多看看Java API的源碼堪置,并不一定要看懂程序躬存,而是看那些大牛的編碼風格,命名風格舀锨,很值得去學習一下岭洲。
比如在API中的類型參數(shù)名字:E (Element)元素
K (Key)鍵
V (Value) 值
就像這樣
//泛型接口
public interface Test<E>{}
//單個類型參數(shù)的泛型類
public class Test1<E> {
public void test(E e){}
}
//多個類型參數(shù)的泛型類
public class Test2<K,V>{}
二、泛型方法
泛型接口和泛型類在聲明上相對簡單些坎匿,看上面的例子就可以了盾剩,對于泛型方法,我們看API中的一個例子替蔬,在java.util.Collections
有一個對集合按照某種規(guī)則進行排序的方法sort()
,方法如下:
public static <T extends Comparable<? super T>> void sort(List<T> list){//...}
泛型方法的聲明需要在返回值前面進行泛型的生命告私,和泛型類和泛型接口一樣,可以聲明多個泛型承桥,用英文逗號隔開驻粟。
泛型方法使我們可以使用未定義在類聲明中的類型參數(shù)。
三凶异、規(guī)則&限制
1.泛型的類型參數(shù)只能是類類型格嗅,不能是簡單類型。
List<int> list = new ArrayList<int>();
/*這樣寫也是錯誤唠帝,是自己粗心大意屯掖,有些想當然了。如果由于自己的失誤給大家?guī)? 誤解襟衰,在這里向大家表示歉意贴铜。
*/
2.泛型的類型參數(shù)可以使用extends語句,例如:
public class Test<T extends List> {//...}
在以上的類聲明中類型參數(shù)只能是List的子類瀑晒,不能為其他類類型 绍坝。請注意,在這里extends關鍵字不能理解成繼承的意思苔悦,因為在這里extends既適用于類也適用于接口轩褐,就如上面那樣,所以在這里extends應該理解為“是一個”的意思玖详。
3.泛型的類型參數(shù)可以有多個把介,就像API中的Map一樣勤讽,
public interface Map<K,V>{//...}
4.同一種泛型對應多個版本,因為參數(shù)類型是不確定的拗踢,但是不同版本的泛型類實例是不兼容的脚牍,包括具有繼承關系的類類型。下面看下面這個例子巢墅。
public class Test{
public static void test(List<Animal> list){}
static class Animal{}
static class Dog extends Animal{}
static class Cat extends Animal{}
public static void main(String[] args){
//創(chuàng)建Animal類型的集合
List<Animal> animalList = new ArrayList<Animal>();
animalList.add(new Animal());
//由于Dog和Cat類繼承自Animal诸狭,所以也可以說Dog和Cat也是Animal類型的,所以可以網(wǎng)Animal類型的集合中添加Dog和Cat的實例
animalList.add(new Dog());
animalList.add(new Cat());
//創(chuàng)建Dog類型的集合
List<Dog> dogList = new ArrayList<Dog>();
dogList.add(new Dog());
dogList.add(new Dog());
//調(diào)用test方法
test(animalList);
test(dogList);//編譯器將會報錯
}
}
在上面的實例中我們首先定義了一個接收Animal類型集合作為參數(shù)的test方法君纫,然后再Main主方法中分別定義了Animal類型和Dog類型的List集合驯遇。
接下來我們調(diào)用test方法將animalList
和dogList
作為參數(shù)傳進去,
這時我們會發(fā)現(xiàn)test(dogList)
會報錯蓄髓。
這是因為將子類集合加入到具有聲明為父類集合的參數(shù)的方法中是不合法的操作叉庐,也就是我們上面說的不同版本的泛型類實例是不兼容的。
那么你可能要疑問:那么我該怎樣使用多態(tài)化集合參數(shù)呢双吆?
方法1.使用通配符類型眨唬?会前,就像下面這樣
...
public static void test(List<?> list){}
...
public static void main(String[] args){
...
test(animalList);
test(dogList);//這樣編譯器就不會報錯了
}
方法2.在聲明泛型時使用extends語句
...
public static <T extends Animal> void test(List<T> list){}
...
public static void main(String[] args){
...
test(animalList);
test(dogList);//這樣編譯器就不會報錯了
}
<b>注意</b>:使用上面兩種方式時好乐,編譯器會組織任何可能破壞形式參數(shù)所指集合的行為,也就是不能在定義的方法中瓦宜,不能向作為參數(shù)的集合中添加任何元素蔚万,但可以刪除元素。
三临庇、其他
數(shù)組也是我們經(jīng)常使用的用來存儲數(shù)據(jù)的一種集合
對于數(shù)組的類型是在運行時期檢查的反璃,對于集合的類型檢查只會發(fā)生在編譯時期。
所以因為多態(tài)的關系假夺,將子類數(shù)組傳入具有聲明為父類數(shù)組的參數(shù)的方法中是完全合法的操作淮蜈。但是如果將子類數(shù)組傳入到方法中后,對該數(shù)組隨意進行賦值操作已卷,會報ArrayStoreException異常梧田,就行下面這樣。
public class Test {
public static void test2(Animal[] animals){
animals[0] = new Cat();
animals[1] = new Animal();
}
public static void main(String[] args){
Animal[] animals = new Animal[3];
Dog[] dogs = new Dog[3];
test2(animals);
test2(dogs);
}
}
在test2()
方法中對參數(shù)數(shù)組進行了賦值操作侧蘸,當將Dog類型的數(shù)組傳入test2()
方法中裁眯,在程序運行時會有ArrayStoreException異常。
因為經(jīng)驗尚淺讳癌,所以如果有錯誤的或者描述不妥的地方穿稳,希望各位讀者幫忙指正。