全文共2352字,預計學習時長12分鐘
圖源:unsplash
作爲Java中關鍵概念,大多數Java代碼庫都會使用泛型,開發人員在某個時候遇到它們也是不可避免的。正確理解泛型對於掌握Java至關重要,這也會對你的面試有所助益。
本文是關於Java中泛型知識的大放送,泛型是什麼,如何在Java中使用,以及它們的優點有哪些,你都能在下文中找到答案。
在Java 5中添加泛型是爲了提供編譯時類型檢查,並消除使用集合類時常見的 ClassCastException 風險。Java中的集合類用於存儲和操作對象組。例如,ArrayList集合類可以存儲任何類型的對象。因爲它被設計成Java基類類型對象的容器。
因此,ArrayList對象可以保存字符串、整數或任何Java類型。在泛型之前,只創建字符串或整數的ArrayList是不可行的。使用泛型定義ArrayList可以容納的對象類型,因此允許創建單個的ArrayList對象類型:
import java.util.ArrayList;
publicclassGenEx1{
publicstaticvoidmain(String []args){
ArrayList<String> al =newArrayList<String>();
al.add("Name");
al.add("Age");
al.add(22); // Compile Error!
}
}
如上例,泛型類型是通過使用尖括號定義的。在本例中,只有String對象可以存儲在ArrayList中。Java中的集合類現在具有泛型類型。接下來,讓我們來看看如何編寫自己的泛型類、接口和方法。
泛型類
在泛型類聲明中,類的名稱後面是類型參數部分。可以使用相同的語法來創建通用接口。類型參數,也稱爲類型變量,是用於指定泛型類型名稱的標識符。泛型類的類型參數部分可以包括一個或多個用逗號分隔的類型參數,這些類也稱爲參數化類。
classTest<K, V>{
private K key;
private V value;
Test(K key, V value){
this.key = key;
this.value = value;
}
public K getKey(){
return key;
}
public V getValue(){
return value;
}
}
publicclassGenEx2{
publicstaticvoidmain(String []args){
Test<String,Integer> pair1 =newTest<String,Integer>("ID",223);
Test<String,Integer> pair2 =newTest<String,Integer>("Age",22);
System.out.println(pair1.getKey() +"="+ pair1.getValue() );
System.out.println(pair2.getKey() +"="+ pair2.getValue() );
}
}
在上例中,測試類有兩個名爲K和 v的類型參數,因此測試類的對象可以存儲兩種不同類型的值。
泛型方法
如果可以編寫一個排序方法來對整數數組、字符串數組或任何支持排序的類型的數組中的元素進行排序,該有多好?
圖源:unsplash
Java泛型方法允許用一個方法聲明指定一組相關類型。這樣能夠編寫單個泛型方法聲明,該聲明可以用不同類型的參數調用。類型參數部分必須在方法返回類型之前指定,類型參數也可以用作方法的返回類型。
publicclassGenEx3{
publicstatic< E >voidprintArray( E[] inputArray ) {
for(E element : inputArray) {
System.out.print(element +" ");
}
System.out.println();
}
publicstaticvoidmain(String args[]){
Integer[] intArray = { 1, 2, 3, 4, 5 };
Double[] doubleArray = { 1.1, 2.2, 3.3, 4.4 };
Character[] charArray = { 'P', 'I', 'Z', 'Z', 'A' };
System.out.print("integerArray contains: ");
printArray(intArray);
System.out.print("doubleArray contains: ");
printArray(doubleArray);
System.out.print("characterArray contains: ");
printArray(charArray);
}
}
在上例中, printArray 方法可以用來打印任何類型數組的元素。
泛型中的有界類型參數
到目前爲止,我們只看到了無界泛型類型參數。無界意味着泛型類型參數可以是我們想要的任何類型,有時可能需要限制允許傳遞給類型參數的類型。例如,對數字進行操作的方法可能只想接受Number類或其子類的實例,爲此使用了有界類型參數。
若要聲明有界類型參數,要列出類型參數的名稱,後跟extends關鍵字,然後是它的上界。
publicabstractclassCage<T extendsAnimal> {
abstractvoidaddAnimal(T animal)
}
classAnimal{}
classDogextendsAnimal{}
classCatextendsAnimal{}
在本例中,Cage類的泛型類型必須始終是Animal或Animal類的一個子類。因此,我們可以將Cat、Dog或Animal類作爲泛型類型參數傳遞。如果需要,還可以爲泛型類型聲明多個界限。上面示例中的抽象類可以按照如下所示進行修改:
public abstract class Cage<T extends Animal& Comparable<T>>
在這裏,類型參數現在必須同時考慮Animal類和Comparable接口。
泛型中的通配符和子類型
問號(?)是泛型中的通配符,表示未知類型。如果希望泛型方法處理所有類型,在本例中可以使用無界通配符。無界通配符由<?>表示,還可以使用綁定通配符。有界通配符有兩種類型,上界通配符和下界通配符。
圖源:unsplash
上界通配符用於放寬對方法中變量類型的限制。例如,假設不知道list是數字、整數還是Double類型。那麼如何得到列表中所有元素的和呢?可以使用上界通配符來解決這個問題:
publicvoid method( List<? extends Number> list){
double sum =0;
for(Number i : list){
sum += i.doubleValue();
}
System.out.println(sum);
}
下界通配符用於增加對方法中變量類型的限制。假設只想向一個列表中添加整數,同時又想接受一個Integer超類型的列表。可以使用一個下界通配符來實現這一點:
publicvoid addIntegers(List<? super Integer> list){
list.add(new Integer(10));
list.add(new Integer(20));
}
雖然 Integer 是Java中 Number 的子類型,但是 List<Integer> 不是 List<Number> 的子類型。它們的共同父類是List<?>。所以泛型類中的子類型是使用通配符完成的:
ArrayList<? extends Integer> intList =newArrayList<>();
ArrayList<? extends Number> numList = intList; // OK
ArrayList<Integer> intList2 =newArrayList<>();
ArrayList<Number> numList2 = intList2; // Compile Error!
diamond操作符,也稱爲diamond語法,是作爲Java 7中的一個新特性引入的。diamond操作符的目的是在創建對象時簡化泛型的使用。
ArrayList<String> al = newArrayList<>();
通過使用diamond操作符,可以簡化字符串ArrayList的聲明。
泛型的好處
講過如何使用泛型之後,讓我們來探討一下,我們爲何要使用泛型呢?使用泛型有三個主要原因:
· 類型安全
· 不需要類型轉換
· 可重用代碼
泛型確保了編譯時的安全性,這允許在編譯代碼時捕獲無效類型。因此,不需要擔心運行時異常。不需要單獨的類型轉換是使用泛型的另一個優點。定義初始類型,然後讓代碼進行轉換。
圖源:unsplash
還可以避免代碼重複。如果沒有泛型,必須針對不同的類型複製和粘貼相同的代碼。使用泛型可以不需要這樣做。
好啦,關於Java中泛型的知識都在這裏了,要好好掌握呀!
一起分享AI學習與發展的乾貨
歡迎關注全平臺AI垂類自媒體 “讀芯術”
(添加小編微信:dxsxbb,加入讀者圈,一起討論最新鮮的人工智能科技哦~)