Java這個高級特性,很多人還沒用過!
點(diǎn)擊上方“碼農(nóng)突圍”,馬上關(guān)注 這里是碼農(nóng)充電第一站,回復(fù)“666”,獲取一份專屬大禮包 真愛,請?jiān)O(shè)置“星標(biāo)”或點(diǎn)個“在看 來源 | https://zhenbianshu.github.io/
前言
泛型是什么
generic,中文意思是通用的、一類的,結(jié)合其應(yīng)用場景,我理解泛型是一種 通用類型。但我們一般指泛型都是指其實(shí)現(xiàn)方式,也就是 將類型參數(shù)化public static void quickSort(int[] data, int start, int end) {
int key = data[start];
int i = start;
int j = end;
while (i < j) {
while (data[j] > key && j > i) {
j--;
}
data[i] = data[j];
while (data[i] < key && i < j) {
i++;
}
data[j] = data[i];
}
data[i] = key;
if (i - 1 > start) {
quickSort(data, start, i - 1);
}
if (i + 1 < end) {
quickSort(data, i + 1, end);
}
}
public static <T extends Comparable<T>> void quickSort(T[] data, int start, int end) {
T key = data[start];
int i = start;
int j = end;
while (i < j) {
while (data[j].compareTo(key) > 0 && j > i) {
j--;
}
data[i] = data[j];
while (data[i].compareTo(key) < 0 && i < j) {
i++;
}
data[j] = data[i];
}
data[i] = key;
if (i - 1 > start) {
quickSort(data, start, i - 1);
}
if (i + 1 < end) {
quickSort(data, i + 1, end);
}
}
當(dāng)參數(shù)類型不明確,可能會擴(kuò)展為多種時。 想聲明參數(shù)類型為 Object,并在使用時用instanceof判斷時。
泛型只能替代Object的子類型,如果需要替代基本類型,可以使用包裝類,至于為什么,會在下文中說明。使用
聲明
<占位符 [,另一個占位符] > 的形式,需要在一個地方同時聲明多個占位符時,使用 , 隔開。占位符的格式并無限制,不過一般約定使用單個大寫字母,如 T 代表類型(type),E 代表元素*(element)等。雖然沒有嚴(yán)格規(guī)定,不過為了代碼的易讀性,最好使用前檢查一下約定用法。class Generics<T> { // 在類名后聲明引入泛型類型
private T field; // 引入后可以將字段聲明為泛型類型
public T getField() { // 類方法內(nèi)也可以使用泛型類型
return field;
}
}
public [static] <T> void testMethod(T arg) { // 訪問限定符[靜態(tài)方法在 static] 后使用 <占位符> 聲明泛型方法后,在參數(shù)列表后就可以使用泛型類型了
// doSomething
}
Comparable<T> 的泛型接口,與此類似的還有 Searializable<T> Iterable<T>等,其實(shí)在接口中聲明與在類中聲明并沒有什么太大區(qū)別。調(diào)用
public static void main(String[] args) {
String[] strArr = new String[2];
// 泛型方法的調(diào)用跟普通方法相同
Generics.quickSort(strArr, 0, 30 );
// 泛型類在調(diào)用時需要聲明一種精確類型
Generics<Long> sample = new Generics<>();
Long field = sample.getField();
}
// 泛型接口需要在泛型類里實(shí)現(xiàn)
class GenericsImpl<T> implements Comparable<T> {
@Override
public int compareTo(T o) {
return 0;
}
}
類型擦除
由來
Generics<Long> 被擦除后是 Generics,我們常用的 List<String> 被擦除后只剩下 List。public static void main(String[] args) {
List<String> stringList = new ArrayList<>();
List<Long> longList = new ArrayList<>();
if (stringList.getClass() == longList.getClass()) {
System.out.println(stringList.getClass().toString());
System.out.println(longList.getClass().toString());
System.out.println("type erased");
}
}
class java.util.ArrayList,兩者類型相同,說明其泛型類型被擦除掉了。signature 字段,其中指向了常量表中泛型的真正類型,所以泛型的真正類型,還可以通過反射獲取得到。實(shí)現(xiàn)
javac 命令編譯成 class 文件后,再使用 javap 命令查看其字節(jié)碼信息:
T 被替換成了 Object 類型,而在 main 方法里 getField 字段時,進(jìn)行了類型轉(zhuǎn)換(checkcast),如此,我們可以看出來 Java 的泛型實(shí)現(xiàn)了,一段泛型代碼的編譯運(yùn)行過程如下:編譯期間編譯器檢查傳入的泛型類型與聲明的泛型類型是否匹配,不匹配則報出編譯器錯誤; 編譯器執(zhí)行類型擦除,字節(jié)碼內(nèi)只保留其原始類型; 運(yùn)行期間,再將 Object 轉(zhuǎn)換為所需要的泛型類型。
Java 的泛型實(shí)際上是由編譯器實(shí)現(xiàn)的,將泛型類型轉(zhuǎn)換為 Object 類型,在運(yùn)行期間再進(jìn)行狀態(tài)轉(zhuǎn)換。實(shí)踐問題
具體類型須為Object子類型
Generics<int> generics = new Generics<int>(); 在編譯期間就會報錯的。邊界限定通配符的使用
<? extends Generics> 是上邊界限定通配符,避開 上邊界 這個比較模糊的詞不談,我們來看其聲明 xx extends Generics, XX 是繼承了 Generics 的類(也有可能是實(shí)現(xiàn),下面只說繼承),我們按照以下代碼聲明:List<? extends Generics> genericsList = new ArrayList<>();
Generics generics = genericsList.get(0);
genericsList.add(new Generics<String>()); // 編譯無法通過
<? super Generics> 是下邊界限定通配符, XX 是 Generics 的父類,所以:List<? super Generics> genericsList = new ArrayList<>();
genericsList.add(new Generics()); // 編譯無法通過
Generics generics = genericsList.get(0);
最佳實(shí)踐
將代碼邏輯拆分為兩部分:通用邏輯和類型相關(guān)邏輯;通用邏輯是一些跟參數(shù)類型無關(guān)的邏輯,如快排的元素位置整理等;類型相關(guān)邏輯,顧名思義,是需要確定類型后才能編寫的邏輯,如元素大小的比較,String 類型的比較和 int 類型的比較就不一樣。 如果沒有類型相關(guān)的邏輯,如 List 作為容器不需要考慮什么類型,那么直接完善通用代碼即可。 如果有參數(shù)類型相關(guān)的邏輯,那么就需要考慮這些邏輯是否已有共同的接口實(shí)現(xiàn),如果已有共同的接口實(shí)現(xiàn),可以使用邊界限定通配符。如快排的元素就實(shí)現(xiàn)了 Compare接口,Object 已經(jīng)實(shí)現(xiàn)了toString()方法,所有的打印語句都可以調(diào)用它。如果還沒有共同的接口,那么需要考慮是否可以抽象出一個通用的接口實(shí)現(xiàn),如打印人類的衣服顏色和動物的毛皮顏色,就可以抽象出一個 getColor()接口,抽象之后再使用邊界限定通配符。如果無法抽象出通用接口,如輸出人類身高或動物體重這種,還是不要使用泛型了,因?yàn)椴幌薅愋偷脑挘唧w類型的方法調(diào)用也就無從談起,編譯也無法通過。

小結(jié)
- END - 最近熱文
? 如何優(yōu)雅記錄 http 請求/ 響應(yīng)數(shù)據(jù)? ? 如何寫出讓同事無法維護(hù)的代碼? ? 86版西游記“紅孩兒”成中科院博士!做CTO身價過億! ? 劉強(qiáng)東的代碼水平到底有多牛? 網(wǎng)友:95年一個晚上賺5萬!
評論
圖片
表情

