[toc]
一、為什么要有泛型
1.1泛型:標簽
1.2 設(shè)計背景:
- 集合容器在設(shè)計階段或聲明階段不能確定這個容器到底實際存的是什么類型的對象棚瘟,所以在 JDK 1.5 之前 只能把元素類型設(shè)計為 Object , JDK1.5 之后使用泛型來解決垦搬。
- 泛型:把元素的類型設(shè)計成一個參數(shù)孽惰,這個類型參數(shù)叫做泛型。
- <font color=red>泛型迂烁,就是允許在定義類、接口時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數(shù)類型递鹉。這個類型參數(shù)將在使用時(例如盟步,繼承或?qū)崿F(xiàn)這個接口,用這個類型聲明變量躏结,創(chuàng)建對象)確定(即傳入實際的類型參數(shù)却盘,也成為類型實參)</font>
二、在集合中使用泛型
集合接口或集合類在 jdk 5.0 時都修改為帶泛型的結(jié)構(gòu)
在實例化集合類時媳拴,可以指明具體的<font color=red>泛型類型</font>
指明完以后黄橘,在集合類或接口總凡是定義類或接口時,<font color=red>內(nèi)部結(jié)構(gòu)(比如:方法屈溉、構(gòu)造器塞关、屬性)</font>使用到類的泛型的位置,都指定為實例化的泛型類型子巾。比如 : add(E e) --> 實例化以后: add(Integer e)
注意點:泛型的類型必須是類帆赢,不能是基本數(shù)據(jù)類型,需要用到基本數(shù)據(jù)類型的位置砰左,拿<font color=red>包裝類</font>替換
如果實例化時匿醒,沒有指明泛型的類型,<font color=red>默認類型為 java.lang.Object </font>類型
2.1 在集合中使用 泛型前的情況:
- 問題一:類型不安全
- 問題二:強轉(zhuǎn)時缠导,可能出現(xiàn) ClassCastException
2.2 類型推斷
List<Integer> list = new ArrayList<>();
三、自定義泛型結(jié)構(gòu)
- 泛型類溉痢、泛型接口僻造;泛型方法
- 要求:如果定義了類是帶泛型的,建議在實例化時指明類的泛型
3.1 關(guān)于自定義泛型類孩饼、泛型接口
-
自定義泛型類
public class Order<T> { String orderName; int orderId; //類的內(nèi)部結(jié)構(gòu)就可以使用類的泛型 T orderT; public Order(){} public Order(String orderName,int orderId,T orderT){ this.orderName = orderName; this.orderId = orderId; this.orderT = orderT; } public T getOrderT(){ return orderT; } public void setOrderT(T orderT){ this.orderT = orderT; } @Override public String toString() { return "Order{" + "orderName='" + orderName + '\'' + ", orderId=" + orderId + ", orderT=" + orderT + '}'; } }
-
如果定義了泛型類髓削,實例化沒有指明類的泛型,則認為此泛型類型為Object 類型
- 經(jīng)驗: 泛型要用就一直用镀娶,要不用立膛,就一直都不用
Order order = new Order(); order.setOrderT(123); order.setOrderT("ABC");
-
建議:實例化時指明類的泛型
Order<String> order1 = new Order<String>("orderAA",1001,"order:AA");
泛型類可能有多個參數(shù),此時應(yīng)將多個參數(shù)一起放在 尖括號內(nèi)。比如< E1,E2,E3>
-
泛型類的構(gòu)造器如下:
public GenericClass(){}
錯誤的是:
public GenericClass<E>(){}
實例化后宝泵,操作原來泛型位置的結(jié)構(gòu)必須與指定的泛型類型一致
-
泛型不同的引用不能相互賦值
- 盡管在編譯時ArrayList< String > 和 ArrayList< Integer> 是兩種類型好啰,但是,在運行時儿奶,只有一個ArrayList 被加載到 JVM 中框往。
ArrayList<String> list1 = null; ArrayList<Integer> list2 = null; //list1 = list2;
靜態(tài)方法中不能使用類的泛型,靜態(tài)方法創(chuàng)建早于泛型的創(chuàng)建闯捎,所以不能使用
-
異常類不能聲明為泛型類
-
錯誤的代碼
//public class MyException<T> extends Exception{}
/*try{ }catch(T t){ }*/
-
-
不能使用new E[] .
//編譯不通過 //T[] arr = new T[10]; //編譯通過 T[] arr = (T[]) new Object();
-
父類有泛型椰弊,子類可以選擇保留泛型也可以選指定泛型類型:
class Father<T1,T2>{ }
-
子類不保留父類的泛型:按需實現(xiàn)
-
沒有類型 擦除
class Son1 extends Father{ //等價于 class Son extends Father<Object,Object>{} }
-
具體類型
class Son2 extends Father<Integer,String>{}
-
-
子類保留父類的泛型 泛型子類
-
全部保留
class Son3<T1,T2> extends Father{}
-
部分保留
class Son4<T2> extends Father<Integer,T2>{}
-
-
3.2 泛型方法:
在方法中出現(xiàn)了泛型的結(jié)構(gòu),泛型參數(shù)與類的泛型參數(shù)沒有任何關(guān)系
泛型方法所屬的類是不是泛型類都沒關(guān)系瓤鼻。
-
泛型方法秉版,可以聲明為靜態(tài)的,原因:泛型參數(shù)是在調(diào)用方法時確定的茬祷。并非在實例化類時確定清焕。
public <E> List<E> copyFromArrayToList(E[] arr){ ArrayList<E> list = new ArrayList<>(); for (E e : arr) { list.add(e); } return list; }
四、泛型在繼承上的體現(xiàn)
雖然類 A 是類B 的父類牲迫,但是 G< A> 和 G< B> 二者不具備子父類關(guān)系耐朴,二者是并列關(guān)系。
-
類A 是 類B 的父類盹憎,但是 G< A> 和 G< B> 是子父類關(guān)系
AbstractList<String> list1 = null; List<String> list2 = null; ArrayList<String> list3 = null; list1 = list3; list2 = list3; List<String> list4 = new ArrayList<>();
五筛峭、通配符的使用
通配符:?
-
類A 是 類B 的父類陪每,G< A> 和 G< B> 是沒有關(guān)系的影晓,二者共同的父類是:G<?>
@Test public void test3(){ List<Object> list1 = null; List<Integer> list2 = null; List<?> list = null; list = list1; list = list2; print(list1); print(list2); } public void print(List<?> list){ Iterator<?> iterator = list.iterator(); while(iterator.hasNext()){ Object obj = iterator.next(); System.out.println(obj); } }
添加:對于 List<?> 就不能向其內(nèi)部添加數(shù)據(jù)。除了添加null之外
-
獲乳莺獭:允許讀取數(shù)據(jù)挂签,讀取的數(shù)據(jù)類型為 Object
List<?> list = null; List<Integer> list1 = new ArrayList<>(); list.add(123); list = list1; Object o = list.get(0); System.out.println(o); //123
5.1 有限制條件的通配符
? extends A: G< ? extends A> 可以作為 G< A> 和 G< B> 的父類的,其中B是A的子類盼产。
-
饵婆? super A: G< ?super A> 可以作為 G< A> 和 G< B> 的父類戏售,其中 B 是 A 的父類侨核。
List<? extends Person> list1 = null; List<? super Person> list2 = null; List<Student> list3 = null; List<Person> list4 = null; List<Object> list5 = null; list1 = list3; list1 = list4; //list1 = list5; //list2 = list3; list2 = list4; list2 = list5;