新聞中心
?前言
泛型機(jī)制在項(xiàng)目中一直都在使用,比如在集合中ArrayList

專注于為中小企業(yè)提供網(wǎng)站制作、網(wǎng)站建設(shè)服務(wù),電腦端+手機(jī)端+微信端的三站合一,更高效的管理,為中小企業(yè)閬中免費(fèi)做網(wǎng)站提供優(yōu)質(zhì)的服務(wù)。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動(dòng)了1000+企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設(shè)實(shí)現(xiàn)規(guī)模擴(kuò)充和轉(zhuǎn)變。
泛型介紹和使用
泛型在類定義時(shí)不會(huì)設(shè)置類中的屬性或方法參數(shù)的具體類型,而是在類使用時(shí)(創(chuàng)建對(duì)象)再進(jìn)行類型的定義。會(huì)在編譯期檢查類型是否錯(cuò)誤, 保證程序的可讀性和安全性。
泛型定義根據(jù)實(shí)際情況可以分為泛型類和泛型方法:
泛型類
public class Point{
private T pointX;
private U pintY;
public Point(T pointX, U pintY) {
this.pointX = pointX;
this.pintY = pintY;
}
public void showPoint() {
System.out.println(pointX);
System.out.println(pintY);
}
}
- 類中引入類型變量,類型變量指的T, U這些,用尖括號(hào)<>括起來, 跟在類名后面。
- 多個(gè)類型變量可以用逗號(hào)分隔。
- 在類中的方法和返回值等地方可以使用類型變量。
- 類型變量采用大寫形式,要求簡(jiǎn)短,一般E表示集合的元素類型,K和V表示key和value等。
- 泛型類使用:Point
泛型方法
public class FxMethod {
public static T getMiddleNumber(T ... numbers) {
return null;
}
public void showNumber(T t, U u) {
System.out.println("t = " + t);
System.out.println("u = " + u);;
}
} - 方法中引入類型變量,在返回類型前添加<>, 中間放置類型變量,多個(gè)類型變量用逗號(hào)分隔。
- 在方法的參數(shù)和返回值等位置可以使用類型變量。
- 泛型方法使用:Integer result = FxMethod.getMiddleNumber(2, 3) 或者 Integer result = FxMethod.
getMiddleNumber(2, 3)。
類型變量的限定
前面講解了泛型一般定義的兩種方式,其中的類型變量沒有任何限定, 這樣在導(dǎo)致一方面在定義泛型的時(shí)候無法使用一些API, 需要強(qiáng)轉(zhuǎn),另一方面在使用的時(shí)候也容易出錯(cuò),那么如何給類型變量添加限定呢?
- 只有通過extends關(guān)鍵字限定,不能通過super關(guān)鍵字。
- 加了限定以后,就可以直接使用限定類相關(guān)的API。
- 多個(gè)限定之間用&符號(hào),比如T extends Number & Comparable。
- 使用泛型時(shí),只能傳入相應(yīng)限定的類,比如傳入Point
就會(huì)報(bào)編譯錯(cuò)誤。
通配符使用
泛型的引入的確解決了很大問題,那它是完美的嗎?
class AnimalWrapper{
private T animal;
AnimalWrapper(T animal) {
this.animal = animal;
}
public void eat() {
animal.eat();
}
}
class Animal {
private String name;
public void eat() {
System.out.println("animal eat -----");
}
}
class Cat extends Animal {
@Override
public void eat() {
System.out.println(" cat eat -----");
}
}
定義一個(gè)AnimalWrapper?,泛型變量中限定為Animal,如果是下面的測(cè)試類,會(huì)怎么樣呢?
會(huì)編譯報(bào)錯(cuò),因?yàn)锳nimalWrapper并不是AnimalWrapper的子類,不能直接傳入。為了解決個(gè)問題,我們引入了通配符,通配符一般是在方法中或者泛型類使用中用到。
AnimalWrapper
- 統(tǒng)配符使用在集合或者方法的參數(shù)返回值中。
- 通配符可以分為無邊界通配符、上邊界通配符和下邊界通配符。
無邊界通配符
通配符無邊界,可以傳入任何類型,沒有限制,相當(dāng)于Object.
基本語法:
>
例子:
public static void printList1(List> list) {
for (Object x:list) {
System.out.println(x);
}
}
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
printList1(list); // ok
List list2 = new ArrayList<>();
list2.add("1");
printList1(list2); // ok
List> list3 = list;
// get只能用Object接受,
Object o = list3.get(0);
list3.add(5); // compile error
list3.add(new Object()); // compile error
} 小結(jié):
- 無邊界通配符相當(dāng)于Object,任何類型都可以傳入,比如List
list, List list2。 - 由于?無法確定是哪種類型,所以只能使用Object類型的變量接收, 比如例子中的: Object o = list3.get(0);
- 如果是無邊界通配符對(duì)應(yīng)的集合類型,不能添加任何元素。因?yàn)闊o法確定集合存放數(shù)據(jù)的類型,鬼知道我們要放什么類型才合適啊。
通配符上界
通配符上界,可以限制傳入的類型必須是上界這個(gè)類或者是這個(gè)類的子類。
基本語法:
extends 上界>
extends Number>//可以傳入的實(shí)參類型是Number或者Number的子類
例子:
public static void printList1(List extends Number> list) {
for (Object x:list) {
System.out.println(x);
}
}
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
printList1(list); // ok
List list1 = new ArrayList<>();
list1.add(1.0D);
printList1(list1); // ok
List list2 = new ArrayList<>();
list2.add("1");
printList1(list2); // compile error
List extends Number> list3 = list;
// get能用上界
Number o = list3.get(0);
// 不能add
list3.add(5); // compile error
list3.add(new Object()); // compile error
} 小結(jié):
- 通配符上界? extends A, 表明所有的是A的類或者子類型可以傳入,比如本例中的``Integer和Double都是Number的`子類,String不是。
- 通配符上界? extends A,確定了類型是A或者是A的子類,那么向集合容器get獲取數(shù)據(jù),肯定是它的上界類A,因?yàn)槠渌诺念惗际茿的子類,比如例子中的Number o = list3.get(0);
- 如果向通配符上界集合中添加元素時(shí),會(huì)失敗。 List extends A>, 說明容器可以容納的是A或者A的子類,但A的子類有很多,不確定放哪個(gè),為了安全性,就直接不讓你add,比如例子中的list3.add(5);,5雖然是Number的子類,依然不能add。
通配符下界
通配符下界,可以限制傳入的類型必須是這個(gè)類或者是這個(gè)類的父類。
基本語法:
super 下界>
super Integer>//代表 可以傳入的實(shí)參的類型是Integer或者Integer的父類類型
例子:
public static void printList1(List super Integer> list) {
for (Object x:list) {
System.out.println(x);
}
}
public static void main(String[] args) {
List list = new ArrayList<>();
list.add(1);
printList1(list); // ok
List list1 = new ArrayList<>();
list1.add(1.0D);
printList1(list1); // compile error
List list2 = new ArrayList<>();
list2.add("1");
printList1(list2); // compile error
List super Integer> list3 = list;
// 不能用下界接收
Integer o = list3.get(0); // compile error
// 能add
list3.add(5); // ok
list3.add(new Number(5)); // compile error
} - 通配符上界? super A, 表明所有的是A的類或者A的父類可以傳入。
- 通配符上界? super A,確定了類型是A或者是A的父類,那么向集合容器get獲取數(shù)據(jù),無法確定是A還是A的某個(gè)父類,所以不能get, Integer o = list3.get(0); // compile error,比如例子中用Integer接收,萬一list3中放的是Object類型,就涼涼了。
- 如果向通配符下界集合中添加元素時(shí),只能添加下屆類的子類。比如例子中的:list3.add(5), list3的通配符是 super Integer>,說明該集合存放的是Integer或者Integer的子類,我只要向容器中放Integer和它的子類都是成立的。
總結(jié)
本文淺談了下泛型和通配符的使用,是自己理解的總結(jié),希望后面的開發(fā)過程中不要再去百度了,如果哪里有問題希望大家指正。
當(dāng)前文章:理解Java泛型和通配符,這次再也忘不了了
標(biāo)題來源:http://www.dlmjj.cn/article/cdcdses.html


咨詢
建站咨詢
