2022-12-29
泛型 類型
泛型類就是在類聲明時通過一個標識表示類中某個屬性的類型或者是某個方法的返回值及參數類型。只有用戶使用該類的時候,該類所屬的類型才能明確。
泛型類的聲明格式具體如下:
[訪問權限] class 類名稱<泛型類型標識1, 泛型類型標識2, ..., 泛型類型標識n> {
[訪問權限] 泛型類型標識 變量名稱;
[訪問權限] 泛型類型標識 方法名稱(參數){};
[訪問權限] 返回值類型聲明 方法名稱(泛型類型標識 變量名稱){};
}
定義好泛型類之后,就可以創建泛型對象。創建泛型對象的語法格式具體如下:
類名稱<參數化類型> 對象名稱 = new 類名稱<參數化類型>();
為了大家更好地理解泛型類以及泛型對象的使用,下面先看一個例子。
import java.util.ArrayList;
public class Example22 {
public static void main(String[] args) {
ArrayList list = new ArrayList(); // 創建ArrayList集合
list.add("abc"); // 添加字符串對象
list.add(10); // 添加Integer對象
list.add(20);
for (Object obj : list) { // 遍歷集合
String str = (String) obj; // 強制轉換成String類型
}
}
}
在上述代碼中,向List集合存入了3個元素,分別是一個字符串和兩個int類型的整數。在取出這些元素時,都將它們強轉為String類型,由于Integer對象無法轉換為String類型,因此程序在運行時會出現java.lang.ClassCastException的異常。
接下來,對上述代碼進行修改,如下所示:
ArrayListlist = new ArrayList();
上面這種寫法就限定了ArrayList集合只能存儲Integer類型元素,改寫后的程序在中編譯時就會出現錯誤提示。修改之后的程序編譯報錯的原因是修改后的代碼限定了集合元素的數據類型,ArrayList這樣的集合只能存儲Integer類型的元素,程序在編譯時,編譯器檢查出String類型的元素與List集合的規定類型不匹配,編譯不通過。
使用泛型可以很好的解決上述問題。接下來,使用泛型再次對上述案例進行改寫。
import java.util.ArrayList;
public class Example23 {
public static void main(String[] args) {
ArrayListlist = new ArrayList(); // 創建ArrayList集合
list.add(10); // 添加Integer對象
list.add(20);
for (Integer ele : list) { // 遍歷集合
System.out.println(ele);
}
}
}
上述代碼從運行結果可以看出,該文件已經可以正常運行。需要注意的是,在使用泛型后,每次遍歷集合元素時,可以指定元素類型為Integer,而不是Object,這樣就避免了在程序中進行強制類型轉換。
6.3 泛型方法
泛型方法的定義與其所在的類是否是泛型類是沒有任何關系的,泛型方法所在的類可以是泛型類,也可以不是泛型類。定義泛型方法代碼如下所示:
[訪問權限] <泛型標識> 返回值類型 方法名稱(泛型標識 參數名稱) {}
接下來通過一個案例來學習泛型方法的定義與使用。
class Dog {
String eat;
Integer age;
publicvoid show(T t) {
System.out.println(t);
}
}
public class Example24 {
public static void main(String[] args) {
Dog dog = new Dog(); // 創建對象
//調用方法,傳入的參數是什么類型,返回值就是什么類型
dog.show("hello");
dog.show(12);
dog.show(12.5);
}
}
上述代碼中,定義了一個泛型方法show(),并將show()方法的參數類型和返回值類型規定為泛型,這樣調用方法時,傳入的參數是什么類型,返回值就是什么類型,如果定義為其他類型,傳入參數就必須是方法指定的參數類型,否則編譯就會出現錯誤。
6.4 泛型接口
在JDK5之后,不僅可以聲明泛型類,也可以聲明泛型接口,聲明泛型接口和聲明泛型類的語法類似,也是在接口名稱后面加上,聲明泛型接口的格式如下所示。
[訪問權限] interface 接口名稱<泛型標識> {}
利用以上格式定義一個泛型接口,如下所示。
interface MyInter{
T getVar();
}
泛型接口定義完成之后,就要定義此接口的子類,定義泛型接口的子類有兩種方式,一種是直接在子類實現的接口中明確地給出泛型類型,另一種是直接在子類后聲明泛型。
6.4.1 直接在接口中指定具體類型
當子類明確泛型類的類型參數變量時,外界使用子類的時候,需要傳遞類型參數變量進來,在實現類中需要定義出類型參數變量。接下來通過一個案例學習這種情況的泛型接口定義。
1.首先定義一個泛型接口。
public interface MyInter{
void show(T t);
}
2.接著定義泛型接口的子類。
Java
public class MyInnerImpl implements MyInter{
@Override
public void show(String s) {
System.out.println(s);
}
}
3.最后定義實現類,進行測試。
public class Example25 {
public static void main(String[] args) {
MyIntermyInter = new MyInnerImpl();
myInter.show("Hello World");
}
}
上述代碼中定義了一個泛型接口MyInter,在泛型接口子類MyInterImpl中實現了MyInter接口。MyInterImpl實現MyInter接口時,直接在實現的接口處指定了具體的泛型類型String,這樣在重寫MyInter接口中的show()方法時直接指明類型為String即可。
6.4.2 在子類的定義上聲明泛型類型
當子類不明確泛型類的類型參數變量,外界使用子類的時候,也需要傳遞類型參數變量進來,在實現類中也需要定義出類型參數變量。接下來通過修改子類MyInnerImpl和測試程序來學習這種情況的泛型接口定義。
1.泛型接口子類MyInnerImpl的實現如下。
public class MyInnerImplimplements MyInter{
@Override
public void show(T t) {
System.out.println(t);
}
}
2.在Example25類中測試代碼實現如下。
public class Example25 {
public static void main(String[] args) {
// ...
MyIntermyInt = new MyInnerImpl<>();
myInt.show(20);
}
}
對比上述案例可知,當子類不確定泛型類的類型參數變量時,在定義對象時泛型可以為任意類型。
6.5 類型通配符
在Java中,數組是可以協變的,例如,Dog extends Animal,那么Animal[]與dog[]是可以兼容的。而集合是不能協變的,也就是說List不是List的父類, 為了解決這個問題,Java泛型為我們提供了類型通配符“?”。
下面我們通過一個案例演示通配符的使用。
import java.util.ArrayList;
import java.util.List;
public class Example26 {
public static void main(String[] args) {
// List集合裝載的是Integer
Listlist = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
test(list);
}
public static void test(List list) {
for(int i = 0; i<list.size(); p="" {<="" i++)="">
System.out.println(list.get(i));
}
}
}
需要注意的是,如果使用通配符“?”接收泛型對象,則通配符“?”修飾的對象只能接收,不能修改,也就是不能設置。下述代碼編譯時編譯器會報錯。
import java.util.ArrayList;
import java.util.List;
public class Example27 {
public static void main(String[] args) {
List list = new ArrayList();
list.add("張三");
// list.add(null);
}
}
由于以上程序將一個字符串設置給泛型所聲明的屬性,因為使用List的形式,所以無法將內容添加到集合中,但可以設置為null值。因此編譯上述代碼,編譯器會報錯,錯誤描述見下。
java: 不兼容的類型: java.lang.String無法轉換為capture#1, 共 ?
通配符表示可以匹配任意類型,任意的Java類都可以匹配,但是當接收一個List集合時,它只能操作數字類型的元素(Float、Integer、Double、Byte等數字類型都行),而如果直接使用通配符的話,該集合就不是只能操作數字了。針對這類問題我們可以設定通配符的上限和下限。
設定通配符上限代碼如下所示:
List<? extends Number>
設定通配符下限代碼如下所示:
<? super Type>
開班時間:2021-04-12(深圳)
開班盛況開班時間:2021-05-17(北京)
開班盛況開班時間:2021-03-22(杭州)
開班盛況開班時間:2021-04-26(北京)
開班盛況開班時間:2021-05-10(北京)
開班盛況開班時間:2021-02-22(北京)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2020-09-21(上海)
開班盛況開班時間:2021-07-12(北京)
預約報名開班時間:2019-07-22(北京)
開班盛況Copyright 2011-2023 北京千鋒互聯科技有限公司 .All Right 京ICP備12003911號-5 京公網安備 11010802035720號