只要認真看過,基本能很熟悉泛型的特性。泛型是JDK1.5以後出現的,好比JDK1.5以前的ArrayList,會出現2個問題數組
1:向ArrayList當中添加對象,添加String和Date均可以,但咱們的本意是添加String,編譯器不會檢查錯誤,會致使不可預知的錯誤。this
2:get()方法獲得一個元素的時候要進行強制類型轉換。
因此泛型的引入很好的解決了這2個問題。.net
一個泛型類以下;code
class Pair<T,E>{ private T first; private E second; public T getFirst() { return first; } public void setFirst(T first) { this.first = first; } public E getSecond() { return second; } public void setSecond(E second) { this.second = second; } }
尖括號中的T,E稱爲類型變量。對象
一個泛型方法的簽名:
public static
類型變量在方法修飾符的後面,返回值的前面。
JVM中是不存在泛型這一說法的,即編譯器在編譯的時候,將類型變量擦除掉了,換成了Bounding Type。上面的Pair類在編譯後,Pair變成這樣了:繼承
class Pair{ private Object first; private Object second; public Object getFirst() { return first; } public void setFirst(Object first) { this.first = first; } public Object getSecond() { return second; } public void setSecond(Object second) { this.second = second; } }
將類型變量替代成了Object。更多的類型替代請繼續往下閱讀;ci
類型擦除帶來的問題:
定義一個Pair的子類get
class extendsPair extends Pair<Date,Date>{ public void setSecond(Date d){ super.setSecond(d); System.out.println("我是字類的方法"); } }
Pair pair=new extendsPair(); pair.setSecond(new Date());
執行結果是:
我是父類的方法
我是字類的方法
爲何會是這樣呢?
由於子類本身定義了一個public void setSecond(Date d)
可是從父類繼承了一個方法是public void setSecond(Object d)
,這是2個不一樣的方法。當用父類的引用指向子類的實例,而後調用詞方法,對於編譯器只會尋找父類的那個方法即public void setSecond(Object d)。而程序員的意圖是調用子類的方法public void setSecond(Date d)
,因此此種狀況,編譯器會爲咱們生成一個橋方法
public void setSecond(Object d){ setSecond((Date)d); }
因此正如結果中那樣,先調用父類的setSecond方法,而後在此方法中調用子類的setSecond方法。
1.類型限定符,用關鍵字extends表示子類型限定
對於下面方法
public People getName(Pair<People,People> p){ return p.getFirst(); }
這個方法,咱們沒法傳入Pair<Student,Studnet>
類型的參數,此時咱們就要用到子類型限定,將此方法改成:
public People getName(Pair<? extends People,? extends People> p){ return p.getFirst(); }
用關鍵字super表示超類型限定,<?>
表示無類型限定。好比一個方法getPairs()咱們要返回Pair<>[]。其中的元素有Pair<Student>,還有Pair<Scientist>
Student和Scientist不存在繼承關係。這是就只能用<?>
2:類型限定注意事項:
看下面代碼
public People getName(Pair<? extends People,? extends People> p){ Student student=new Student(); p.setFirst(student); return p.getFirst(); }
p.setFirst(student)會報錯,由於Pair<? extends People,? extends People>的setFirst方法是
public void setFirst(<? extends People first) { this.first = first; }
形參是People的某子類,可是編譯器不能肯定Student是否是這個子類的子類。可是對於get方法,總能將返回類型轉型成People類。相應的使用超類型限定,get()方法會報錯。
1:不能在泛型類的靜態上下文中定義含有類型變量的靜態成員,如:
class Pair<T,E>{ private static T name; ....
只是對於泛型類來講,如上面普通類中能夠存在靜態方法。這個緣由很簡單,好比Pair<String,String>和Pair<Date,Date>
這2個對象,那麼這兩個對象要共享name,那麼變量name是什麼類型呢?存在衝突。
2:泛型類不能繼承異常類,也不能被拋出
由於泛型類不能繼承Throwable,可是類型變量能夠被拋出,如:
public static <T extends Throwable> T get(T t) throws T{ return t; }
3:泛型數組是不合法的
不能建立這樣的數組:
Pair<String,String>[] pairs=new Pair<String,String>[10];
由於實際上paris是Pair[]類型的,因此咱們添加Date類型的元素,編譯器是不會發現的。這會產生難以定位的錯誤。可是咱們能夠用下面的方式來定義泛型數組。
Pair<String,String>[] pairs=(Pair<String, String>[])(new Pair[10]);
4:不能實例化類型變量
不能出現 new T(),new T[]這樣的src。由於通過類型擦除後,T均變爲BoundingType。這樣的操做沒有意義。
5:類型變量不能是raw類型。