目錄
一.什么是泛型
二.Java中為什么要使用泛型
三.泛型的語法
四.泛型類的使用
五.泛型的編譯機制(擦除機制)
六.泛型的上界
一.什么是泛型
泛型(Generics)是Java SE 5中引入的一個新特性,可以使Java中的類和方法具有更廣泛的類型范圍。通俗的說,它使得我們可以在定義類和方法時指定一個或多個類型參數(shù),從而可以在不考慮具體類型的情況下,代碼中直接使用這些類型參數(shù)。泛型可以增強代碼的安全性、可讀性和可重用性。例如,可以使用泛型實現(xiàn)容器類(如ArrayList、HashMap)等。在使用泛型時,需要在編寫代碼時指定泛型類型,這樣可以在編譯期間檢查代碼的類型安全性。
二.Java中為什么要使用泛型
一般的類和方法,只能使用具體的類型::要么是基本類型,要么是自定義的類。如果要編寫可以應(yīng)用于多種類型的代碼,這種刻板的限制對代碼的束縛就會很大。
----- 來源《Java編程思想》對泛型的介紹
Java中的泛型是一種允許在編寫代碼時指定類型參數(shù)的能力。使用泛型可以使代碼更加通用且類型安全。通過使用泛型,程序員可以編寫一個方法或類,該方法或類在實例化時可以接受不同類型的參數(shù)。泛型是將數(shù)據(jù)類型參數(shù)化,進行傳遞這樣可以減少代碼的重復(fù),并提高代碼的可讀性和可維護性。
假如我們要實現(xiàn)一個數(shù)組,使得其中能夠存放任意數(shù)據(jù)類型的元素,想存放整形,又想存放字符型,又想存放引用型該怎么辦呢?我們可以聯(lián)想一下之前認識過的Object類,Object類是所有類的父類,那我們將數(shù)組置為Object類可以嗎?
class MyArray {
public Object[] array = new Object[10];
public Object getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,Object val) {
this.array[pos] = val;
}
}
public static void main(String[] args) {
MyArray myArray = new MyArray();
myArray.setVal(0, 10);//整形可以存放
myArray.setVal(1, "hello");//字符串也可以存放
String ret = myArray.getPos(1);//編譯報錯,原因是因為我們數(shù)組的類型是Object類型
//但是我們這里接收的元素卻是String類型
//也就是說我們相當(dāng)于進行了向下轉(zhuǎn)型,所以這里會報錯
//如果我們進行強制轉(zhuǎn)化就可以解決這個問題
//String ret = (String) myArray.getPos(1);
System.out.println(ret);
}
?我們會發(fā)現(xiàn)在這種情況下,整體的語法其實是不靈活的,雖然當(dāng)前數(shù)組任何數(shù)據(jù)都可以存放,但是更多情況下,我們還是希望他只能夠持有一種數(shù)據(jù)類型,而不是同時持有這么多類型。
所以泛型的主要目的就是指定當(dāng)前的容器,要持有什么類型的對象,讓編譯器去做檢查。此時就需要把類型作為參數(shù)傳遞,需要什么類型,就傳入什么類型。
三.泛型的語法
在充分認識了泛型的必要性和作用后,我們來看看如何使用它:在Java中,泛型的使用方式是通過在類名或方法名后面加上尖括號,然后在尖括號里指定類型參數(shù)。具體語法如下:
class 泛型類名稱<類型形參列表> {
// 這里可以使用類型參數(shù)
}
class ClassName<T1, T2, ..., Tn> {
}
class 泛型類名稱<類型形參列表> extends 繼承類/* 這里可以使用類型參數(shù) */ {
// 這里可以使用類型參數(shù)
}
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分類型參數(shù)
}
可以通過泛型實例化一個泛型對象
泛型類<類型實參> 變量名; // 定義一個泛型類引用
new 泛型類<類型實參>(構(gòu)造方法實參); // 實例化一個泛型類對象
MyArray<Integer> list = new MyArray<Integer>();
當(dāng)編譯器可以根據(jù)上下文推導(dǎo)出類型實參時,可以省略類型實參的填寫
MyArray<Integer> list = new MyArray<>(); // 可以推導(dǎo)出實例化需要的類型實參為 Integer
泛型只能接受類,所有的基本數(shù)據(jù)類型必須使用包裝類?
四.泛型類的使用
對于我們剛才的數(shù)組,我們就可以如下設(shè)置為一個泛型數(shù)組
class MyArray<T> {
public T[] array = (T[])new Object[10];//1
//public T[] array;
public T getPos(int pos) {
return this.array[pos];
}
public void setVal(int pos,T val) {
this.array[pos] = val;
}
}
public static void main(String[] args) {
MyArray<Integer> myArray1 = new MyArray<>();//2
myArray1.setVal(0,10);
myArray1.setVal(1,12);
MyArray<String> myArray2 = new MyArray<>();//3
myArray2.setVal(0,"hello");
myArray2.setVal(1,"world");
MyArray<Float> myArray3 = new MyArray<>();//4
myArray3.setVal(0,1.23f);
myArray3.setVal(1,3.14f);
}
在上述代碼塊中
類名后的 <T> 代表占位符,表示當(dāng)前類是一個泛型類,常用的其他名稱有:
- E 表示 Element
- K 表示 Key
- V 表示 Value
- N 表示 Number
- T 表示 Type
- S, U, V 等等... ...
注釋1處,不能new泛型類型的數(shù)組,也就是說下面這樣的代碼是錯誤的
T[] arrary = new T[5];//是不對的
注釋2處,類型后加入 <Integer> 指定當(dāng)前類型,注釋3,4處同理
五.泛型的編譯機制(擦除機制)
Java的類型擦除機制是指在編譯期間將泛型的類型參數(shù)替換為其邊界或Object類型,從而實現(xiàn)泛型代碼運行時無需知曉實際類型參數(shù),也就是說泛型的類型參數(shù)在運行時是被擦除了的。這個機制是為了兼容Java語言的舊版本,同時也可以減少代碼重復(fù),使得代碼更加簡潔。
舉個例子來說,:
????????假如有一個泛型類List<T>,其中的T可以指定任何類型,但是在運行時,List<T>的實際類型是List<Object>。那么,當(dāng)我們在使用List<T>時,編譯器會自動擦除類型參數(shù)T,然后將List<T>替換為List<Object>,這樣就可以在運行時使用Object類型來處理元素。
????????在編譯期間,泛型類型參數(shù)String被擦除了,List<String>被替換成了List<Object>,而在運行時,get方法返回的是Object類型,需要強制轉(zhuǎn)換為String類型,也就是說,我們無法在運行時獲取到類型參數(shù)的具體值,因為編譯器已經(jīng)將其擦除了。
泛型到底是如何進行編譯的?這曾經(jīng)作為面試題進行考察過,泛型的語法實際上是非常復(fù)雜不容易理解的,我們需要借助他的字節(jié)碼文件去觀察,使用命令:javap -c 查看字節(jié)碼文件
也就是說在編譯的過程當(dāng)中,將所有的T替換為Object這種機制,我們稱為:擦除機制
這個類型擦除機制也給開發(fā)帶來了一些限制和挑戰(zhàn),比如不能在運行時獲取泛型參數(shù)的具體類型,泛型數(shù)組的創(chuàng)建受到限制等。但是通過一些技巧和設(shè)計模式,我們可以在一定程度上繞過這些限制,讓代碼更加靈活和可擴展。
六.泛型的上界
在定義泛型類時,有時需要對傳入的類型變量做一定的約束,可以通過類型邊界來約束,語法:
class 泛型類名稱<類型形參 extends 類型邊界> {
//... ...
}
例如:
public class MyClass<T extends MyClass2> {
// ...
}
上述代碼中,泛型類型T的上界是MyClass2,這意味著在使用MyClass時,只能傳入MyClass2或其子類作為T的實際類型參數(shù)。這樣做可以確保在類型安全的前提下,使用泛型類型時具有更大的靈活性和可擴展性。
假設(shè)我們有一個泛型類Box<T>
,我們希望確保這個類型參數(shù)T必須是實現(xiàn)了Comparable接口的類。我們可以使用泛型的上界<T extends Comparable<T>>
來實現(xiàn)這個目標(biāo),示例代碼如下:
public class Box<T extends Comparable<T>> {
private T value;
public Box(T value) {
this.value = value;
}
public T getValue() {
return value;
}
public boolean isGreaterThan(Box<T> otherBox) {
return value.compareTo(otherBox.getValue()) > 0;
}
}
在這個示例中,我們使用<T extends Comparable<T>>
來定義類型參數(shù)上界,確保T必須是實現(xiàn)了Comparable接口的類。這樣,我們就可以在isGreaterThan()
方法中使用value.compareTo()
方法來比較value
字段和另一個Box
對象的值了。文章來源:http://www.zghlxwxcb.cn/news/detail-752654.html
??本次的分享就到此為止了,希望我的分享能給您帶來幫助,也歡迎大家三連支持,你們的點贊就是博主更新最大的動力!
如有不同意見,歡迎評論區(qū)積極討論交流,讓我們一起學(xué)習(xí)進步!
有相關(guān)問題也可以私信博主,評論區(qū)和私信都會認真查看的,我們下次再見
文章來源地址http://www.zghlxwxcb.cn/news/detail-752654.html
到了這里,關(guān)于詳解Java中的泛型(泛型的語法,擦除機制,泛型的上界)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!