在沒有介紹泛型的使用時想想我們在哪些地方使用泛型的居多,那麼一定是集合中。在前面的集合中已經看到了使用到泛型了,今天來看下泛型具體的概念及用法。
泛型:
要使程式碼能夠應用於“某種具體的型別而不是一個具體的介面或類”。增加了泛型支援後的集合,完全可以記住集合中元素的型別,並可以在編譯時檢查集合中元素的型別,如果試圖向集合中新增不滿足型別要求的物件,編譯器就會提示錯誤。增加泛型後的集合,可以讓程式碼更加簡潔,程式更加健壯(Java泛型可以保證如果程式在編譯時沒有發出警告,執行時就不會產生ClassCastException異常)。除此之外,Java泛型還增強了列舉類、反射等方面的功能
當建立帶泛型宣告的自定義類,為該類定義構造器時,構造器名還是原來的類名,不要增加泛型宣告。
例如,為Apple類定義構造器,其構造器名依然是Apple,而不是
Apple
呼叫該構造器時卻可以使用Apple的形式,當然應該為T形參傳入實際的型別引數。Java 7提供了菱形語法,允許省略<>中的型別實參。
元組:
將一組物件直接打包儲存於其中的一個單一的物件。這個容器物件允許讀取其中的元素,但是不允許對其存放新的物件(這也稱為:資料傳送物件)
比如一個二維的元組:
public class TwoTuple{ public final A first; public final B second; public TwoTuple(A a, B b){ first = a; second = b;} public String toStirng() { return “(”+first+“,”+second+“)”; }}
用泛型類構造一個堆疊類:
下面的例子使用了末端哨兵來判斷堆疊何時為空,這個末端哨兵在構造LinkedStack時建立,然後每呼叫一次push()方法,就會建立一個Node物件,並將其連結到前一個Node物件。
public class LinkedStack
泛型介面:
public interface Generator{T next();}
用泛型介面實現生成Fibonacci數列:
public class Fibonacci implements Generator
泛型方法:
泛型方法使得該方法能夠獨立於類而產生變化。無論何時,只要你能做到,就應該儘量使用泛型方法。也就是說如果使用泛型方法可以取代整個類泛型化,那麼就應該使用泛型方法,因為他可以使得事情更清楚明白。
定義泛型方法:修飾符 返回引數 方法名(接收引數){}
public class MyUtils{泛型中的型別轉換,在未知型別時不能進行強轉:用下面方式應該先判斷List<?>[] lsa=new ArrayList<?>[10];Object[] oa=(Object[]) lsa;List
泛型邊界萬用字元
泛型的上限:?extends 型別。
泛型的下限:?super 型別。
如果要從集合中讀取型別T的資料,並且不能寫入 可以使用 ? extends 萬用字元;(Producer Extends)
如果要從集合中寫入型別T的資料,並且不需要讀取,可以使用 ? super 萬用字元;(Consumer Super)
//
上界的list只能get不能add,下屆的list只能add不能get
編譯器可以支援像上轉型,不支援像下轉型。
PECS參考:https://blog。51cto。com/flyingcat2013/1616068
泛型擦除:
在泛型程式碼內部,無法獲取任何有關泛型引數型別的資訊。java使用泛型擦除,比如List 和List 在執行時都是相同的型別,均被擦除為“原生”型別即List。 泛型擦除就是被擦除為父類。保留了型別的上限
比如:
List
list
=
new
ArrayList<>();
//型別被擦除了,保留的是型別的上限,String的上限就是Object
List
list1 =
list
;
泛型的面試題
Q&A Java中的泛型是什麼 ? 使用泛型的好處是什麼?
在集合中儲存物件並在使用前進行型別轉換是多麼的不方便。泛型防止了那種情況的發生。它提供了編譯期的型別安全,確保你只能把正確型別的物件放入 集合中,避免了在執行時出現ClassCastException
Q&A Java的泛型是如何工作的 ? 什麼是型別擦除 ?
泛型是透過型別擦除來實現的,編譯器在編譯時擦除了所有型別相關的資訊,所以在執行時不存在任何型別相關的資訊。例如 List在執行時僅用一個List來表示。這樣做的目的,是確保能和Java 5之前的版本開發二進位制類庫進行相容。你無法在執行時訪問到型別引數,因為編譯器已經把泛型型別轉換成了原始型別。
Q&A什麼是泛型中的限定萬用字元和非限定萬用字元 ?
限定萬用字元對型別進行了限制。有兩種限定萬用字元,一種是它透過確保型別必須是T的子類來設定型別的上界,另一種是它透過確保型別必須是T的父類來設定型別的下界。泛型型別必須用限定內的型別來進行初始化,否則會導致編譯錯誤。另一方面表 示了非限定萬用字元,因為可以用任意型別來替代
Q&A List 上界 和List 下界 之間有什麼區別 ?
上界的list只能get不能add,下屆的list只能add不能get
編譯器可以支援像上轉型,不支援像下轉型。
Q&A 你可以把List傳遞給一個接受List引數的方法嗎?
因為List可以儲存任何型別的物件包括String, Integer等等,而List卻只能用來儲存Strings。
List objectList;List stringList;objectList = stringList; //compilation error incompatible typespublic static void main(String[] args) { List
在泛型的面試中很大一部分會出現泛型邊界問題,以及泛型的擦除。這是常常會問及的,所以我們需要格外的注意。