您好,登錄后才能下訂單哦!
這篇文章主要介紹Java中泛型與通配符的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
題外話: 泛型與通配符是Java語(yǔ)法中比較難懂的兩個(gè)語(yǔ)法,學(xué)習(xí)泛型和通配符的主要目的是能夠看懂源碼,實(shí)際使用的不多。
《Java編程思想》上有這么一句話:一般的類和方法,只能使用具體的類型: 要么是基本類型,要么是自定義的類。如果要編寫可以應(yīng)用于多種類型的代碼,這種刻板的限制對(duì)代碼的束縛就會(huì)很大。 所以從Java5開始引入了泛型機(jī)制,這個(gè)泛型是什么意思呢?由于一般的類和方法只能使用一種具體得類型,這就使代碼受到了很大的束縛,比如一個(gè)求三個(gè)數(shù)中最大值的方法,假設(shè)一開始方法中的參數(shù)列表的類型是Integer
,你從三個(gè)整型數(shù)據(jù)中找出一個(gè)最大值沒有任何問(wèn)題,這個(gè)程序能夠完美地運(yùn)行,但是你要找三個(gè)浮點(diǎn)數(shù)中的最大值時(shí),這個(gè)程序編譯都通不過(guò),這時(shí)你可以選擇另寫一個(gè)重載方法將參數(shù)列表和實(shí)現(xiàn)功能都基于Double
再實(shí)現(xiàn)一遍,這樣也可以解決問(wèn)題,但是,你想過(guò)一個(gè)問(wèn)題沒有,萬(wàn)一有一萬(wàn)甚至一百萬(wàn)種類型需要求三個(gè)對(duì)象中最大那一個(gè),那應(yīng)該怎么辦,寫一百萬(wàn)個(gè)重載方法?這是不可能的,為了解決這種類型的問(wèn)題,引入了泛型,泛型實(shí)現(xiàn)了參數(shù)化類型的概念,使代碼可以應(yīng)用多種類型,通俗說(shuō)泛型就是“適用于許多許多類型”的意思。 使用泛型可以將類型作為“參數(shù)”傳遞至類,接口,方法中,這樣類和方法就可以具有最廣泛的表達(dá)能力,不需要因?yàn)橐粋€(gè)參數(shù)不同而去另建類型。
注意:任意的基本類型都不能作為類型參數(shù)。
我們通過(guò)一段代碼來(lái)認(rèn)識(shí)泛型,首先看下面一段不使用代碼的泛型的代碼:
/** * 不使用泛型 */ class A { } class Print { private A a; public Print(A a) { setA(a); System.out.println(this.a); } public void setA(A a) { this.a = a; } public A getA() { return this.a; } } public class Generic { public static void main(String[] args) { Print print = new Print(new A()); } }
//output:A@1b6d3586
不使用泛型取創(chuàng)建一個(gè)類沒有任何問(wèn)題,但是這個(gè)類的重用性就不怎么樣了,它只能持有類A
的對(duì)象,不能持有其他任何類的對(duì)象,我們不希望為碰到的每種類型都編寫成一個(gè)新的類,這是不現(xiàn)實(shí)的。我們學(xué)習(xí)類的時(shí)候,知道Object
類是所有類的父類,所以Object
類可以接受所有的類型引用,我們可以讓Print
類持有Object
類型的對(duì)象。
/** * 使用Object類 */ class B{ } class Print1 { private Object b; public Print1(Object b) { setB(b); System.out.println(this.b); } public void print(Object b) { setB(b); System.out.println(this.b); } public void setB(Object b) { this.b = b; } } public class Generic1 { public static void main(String[] args) { Print1 print1 = new Print1(new B());//打印B類型 int i = 2022; print1.print(i);//打印整型類型 print1.print("這是一個(gè)字符串對(duì)象!");//打印字符串類型 } }
//output:
//B@1b6d3586
//2022
//這是一個(gè)字符串對(duì)象!
Print1
可以接收并打印任何類型,但是這并不是我們想要的結(jié)果,你想想如果實(shí)現(xiàn)的是一個(gè)順序表類,里面是通過(guò)一個(gè)數(shù)組來(lái)實(shí)現(xiàn),如果這個(gè)數(shù)組什么類型都可以接收,那就非?;靵y了,取出數(shù)據(jù)的時(shí)候不能確定取出的到底是什么類型的數(shù)據(jù),而且取出的數(shù)據(jù)是Object
類,需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換,那能不能實(shí)現(xiàn)指定類持有什么類型的對(duì)象并且編譯器能夠檢查類型的正確性。 泛型就完美實(shí)現(xiàn)了這個(gè)目的,下面我們將上述代碼改寫成泛型類,那么首先得知道泛型的語(yǔ)法,泛型類創(chuàng)建語(yǔ)法如下:
class 類名<泛型參數(shù)列表> {
權(quán)限修飾 泛型參數(shù) 變量名;//泛型成員變量
權(quán)限修飾 返回值類型 方法名 (參數(shù)列表){}//參數(shù)列表和返回值類型可以是泛型
}
例如:
class Print2<T> { private T c; public void print(T c) { setC(c); System.out.println(this.c); } public void setC(T c) { this.c = c; } }
泛型類的使用語(yǔ)法如下:
泛型類<類型實(shí)參> 變量名; // 定義一個(gè)泛型類引用
new 泛型類<類型實(shí)參>(構(gòu)造方法實(shí)參); // 實(shí)例化一個(gè)泛型類對(duì)象
例如:
Print2<Integer> print3 = new Print2<Integer>();
使用泛型實(shí)現(xiàn)一個(gè)類,并使用它:
/** * 使用泛型 */ class C{ } class Print2<T> { private T c; public void print(T c) { setC(c); System.out.println(this.c); } public void setC(T c) { this.c = c; } } public class Generic2{ public static void main(String[] args) { Print2<C> print2 = new Print2<>();//打印C類型 print2.print(new C()); Print2<Integer> print3 = new Print2<>();//打印整型類型 print3.print(2022); Print2<String> print4 = new Print2<>();//打印字符串類型 print4.print("這是一個(gè)字符串對(duì)象!"); } }
/**
* output:
*C@1b6d3586
* 2022
* 這是一個(gè)字符串對(duì)象!
*/
類名后的 <T>
代表占位符,表示當(dāng)前類是一個(gè)泛型類。
【規(guī)范】類型形參一般使用一個(gè)大寫字母表示,常用的名稱有:
E 表示 Element
K 表示 Key
V 表示 Value
N 表示 Number
T 表示 Type
S, U, V 等等 - 第二、第三、第四個(gè)類型
//一個(gè)泛型類 class ClassName<T1, T2, ..., Tn> { }
使用泛型類時(shí),指定了這個(gè)類的對(duì)象持有的類型,則該對(duì)象只能接收該類型的對(duì)象,傳入其他類型對(duì)象,編譯器會(huì)報(bào)錯(cuò),并且接收泛型類中泛型方法的返回值時(shí),不需要進(jìn)行強(qiáng)制類型轉(zhuǎn)換(向下轉(zhuǎn)型),而使用Object
類需要強(qiáng)制類型轉(zhuǎn)換。
使用泛型類時(shí),可以通過(guò)泛型類型中傳入的類型來(lái)推導(dǎo)實(shí)例化該泛型類時(shí)所需的類型參數(shù),換個(gè)說(shuō)法,定義泛型對(duì)象時(shí),前面的尖括號(hào)內(nèi)必須指定類型,后面實(shí)例化時(shí)可以不指定。如:
Print2<Integer> print3 = new Print2<>();//后面尖括號(hào)內(nèi)可省略
裸類型其實(shí)很好理解,就是一個(gè)泛型類,你不去指定泛型對(duì)象持有的類型,這樣的一個(gè)類型就是裸類型。 比如:
public static void main(String[] args) { Print2 print2 = new Print2(); print2.print(2022); print2.print("字符串"); }
//output:
//2022
//字符串
我們不要自己去使用裸類型,裸類型是為了兼容老版本的 API 保留的機(jī)制。
介紹泛型的擦除機(jī)制之前,我們先來(lái)了解泛型數(shù)組·,先說(shuō)結(jié)論,在Java中不允許實(shí)例化泛型數(shù)組,如果一定要建立一個(gè)泛型數(shù)組,正確的做法只能通過(guò)反射來(lái)實(shí)現(xiàn),當(dāng)然有一個(gè)“捷徑”可以不使用反射來(lái)創(chuàng)建泛型數(shù)組。創(chuàng)建的代碼如下:
1.通過(guò)捷徑創(chuàng)建,大部分情況下不會(huì)出錯(cuò)。
public class MyArrayList<T> { public T[] elem ; private int usedSize; public MyArrayList(int capacity) { this.elem = (T[])new Object[capacity]; } }
2.通過(guò)反射創(chuàng)建,現(xiàn)在只給代碼,具體為什么要這么做后續(xù)介紹反射再說(shuō)。
public class MyArrayList<T> { public T[] elem ; private int usedSize; public MyArrayList(Class<T> clazz, int capacity) { this.elem = (T[]) Array.newInstance(clazz, capacity); } }
我們先來(lái)實(shí)現(xiàn)一個(gè)簡(jiǎn)單的泛型順序表,不考慮擴(kuò)容問(wèn)題,只實(shí)現(xiàn)簡(jiǎn)單的增刪操作,來(lái)看看構(gòu)造方法部分編譯后的反匯編。
import java.lang.reflect.Array; public class MyArrayList<T> { public T[] elem ; private int usedSize; public MyArrayList(int capacity) { this.elem = (T[])new Object[capacity]; } public MyArrayList(Class<T> clazz, int capacity) { this.elem = (T[]) Array.newInstance(clazz, capacity); } }
我們發(fā)現(xiàn)所有的泛型占位符T
都被擦除替換成Object
了,這就說(shuō)明Java的泛型機(jī)制是在編譯期實(shí)現(xiàn)的,而泛型機(jī)制實(shí)現(xiàn)就是通過(guò)像這樣的擦除機(jī)制實(shí)現(xiàn)的,并在編譯期間完成類型的檢查。
我們通過(guò)打印持有不同類型的MyArrayList
類來(lái)看看,泛型機(jī)制到底是不是不會(huì)出現(xiàn)在運(yùn)行期間,如果是的話,打印出的類型都應(yīng)該是MyArrayList
。
public static void main(String[] args) { MyArrayList<Integer> list1 = new MyArrayList<>(10); MyArrayList<String> list2 = new MyArrayList<>(10); System.out.println(list1); System.out.println(list2); }
/**
* output:
* MyArrayList@1b6d3586
* MyArrayList@4554617c
*/
我們發(fā)現(xiàn)打印的類型是一樣的,都是MyArrayList
,所以可以得出一個(gè)結(jié)論,泛型是發(fā)生在編譯期,泛型的類型檢查是在編譯期完成的,泛型的實(shí)現(xiàn)是通過(guò)擦除機(jī)制實(shí)現(xiàn)的,類后面的占位符都會(huì)被擦除,其他的占位符都會(huì)被替換成Object
。當(dāng)然,這是在泛型參數(shù)沒有指定上界的情況下,如果存在上界,那占位符會(huì)擦除成上界的類型或接口,其實(shí)沒有指定上界,上界默認(rèn)為Object
,什么是泛型上界,噓,等一下再說(shuō)。
根據(jù)擦除機(jī)制,也能解釋為什么Java當(dāng)中不能實(shí)例化泛型數(shù)組了,因?yàn)榉盒蛿?shù)組前面的占位符會(huì)被擦除成Object
,實(shí)際上是創(chuàng)建一個(gè)Object
數(shù)組,而Object
數(shù)組中什么類型都能放,這就導(dǎo)致取數(shù)據(jù)時(shí)不安全,因?yàn)槟悴荒艽_定數(shù)組里面存放的元素全部都是你預(yù)期的類型,所以為了安全,Java不允許實(shí)例化泛型數(shù)組。
在定義泛型類時(shí),有時(shí)需要對(duì)傳入的類型變量做一定的約束,可以通過(guò)類型邊界來(lái)約束。
class 泛型類名稱<類型形參 extends 類型邊界> {
...
}
例如:Number
是Integer
,Float
,Double
等相關(guān)數(shù)字類型的父類。
public class MyArrayList<T extends Number> { }
那么這個(gè)MyArrayList
泛型類只能指定持有Number
類以及Number
的子類,像這樣就給泛型的類型傳參做了約束,這個(gè)約束就是泛型的上界,泛型類被類型邊界約束時(shí),只能指定泛型類持有類型邊界這個(gè)類及其子類。
MyArrayList<Integer> list1 = new MyArrayList<>(10);//正確 MyArrayList<Double> list2 = new MyArrayList<>(10);//正確 MyArrayList<String> list3 = new MyArrayList<>(10);//錯(cuò)誤,因?yàn)镾tring不是Number的子類
假設(shè)需要設(shè)計(jì)一個(gè)泛型類,能夠找出數(shù)組中最大的元素。
class MaxVal<T extends Comparable<T>> { public T max(T[] data) { T max = data[0]; for (int i = 0; i < data.length; i++) { if (max.compareTo(data[i]) < 0) max = data[i]; } return max; } }
由于引用類型的比較需要使用Comparable
接口來(lái)判斷大小,所以所傳入的類需要實(shí)現(xiàn)Comparable
接口,上面這個(gè)泛型的類型參數(shù)的上界是一個(gè)特殊的上界,表示所傳入的類型必須實(shí)現(xiàn)Comparable
接口,不過(guò)實(shí)現(xiàn)了Comparable
接口的類,那也就是Comparable
的子類了,綜上,像這樣類似需要通過(guò)實(shí)現(xiàn)某一個(gè)接口來(lái)達(dá)到預(yù)期功能的類型,使用泛型時(shí)需指定泛型的上界,并且該傳入的類型必須實(shí)現(xiàn)該上界接口。
有泛型類,那么就一定有泛型接口,泛型方法,其中泛型接口與泛型類的創(chuàng)建和使用是一樣的,所以我們重點(diǎn)介紹泛型方法的創(chuàng)建與使用。 創(chuàng)建泛型方法的基本語(yǔ)法:
方法限定符 <類型形參列表> 返回值類型 方法名稱(形參列表) { ... }
例如上面實(shí)現(xiàn)求數(shù)組中最大元素泛型版的方法如下:
class MaxVal<T extends Comparable<T>> { public <T extends Comparable<T>> T max(T[] data) { T max = data[0]; for (int i = 0; i < data.length; i++) { if (max.compareTo(data[i]) < 0) max = data[i]; } return max; } }
對(duì)于非static
修飾的靜態(tài)方法, <類型形參列表>可以省略,上述代碼可以變成:
class MaxVal<T extends Comparable<T>> { public T max(T[] data) { T max = data[0]; for (int i = 0; i < data.length; i++) { if (max.compareTo(data[i]) < 0) max = data[i]; } return max; } }
但是,如果是一個(gè)static
修飾的靜態(tài)方法,<類型形參列表>不可以省略,因?yàn)殪o態(tài)方法不依賴與對(duì)象,它的使用不用實(shí)例化對(duì)象,所以必須有單獨(dú)的類型參數(shù)列表來(lái)指定持有的對(duì)象類型。
class MaxVal<T extends Comparable<T>> { public static <T extends Comparable<T>> T max(T[] data) { T max = data[0]; for (int i = 0; i < data.length; i++) { if (max.compareTo(data[i]) < 0) max = data[i]; } return max; } }
和泛型類一樣,泛型方法也有類型推導(dǎo)的機(jī)制,如果不使用類型推導(dǎo),那么泛型方法是這么使用的:
使用類型推導(dǎo)圖中畫圓圈部分可以省略。
在泛型類中沒有如下的父子類關(guān)系:
public class MyArrayList<E> { ... } // MyArrayList<Object> 不是 MyArrayList<Number> 的父類型 // MyArrayList<Number> 也不是 MyArrayList<Integer> 的父類型
但是使用通配符這兩種類是有符子類關(guān)系的。
?
就是一個(gè)通配符,用與泛型的使用,與泛型不同的是,泛型T
是確定的類型,傳入類型實(shí)參后,它就確定下來(lái)了,而通配符更像是一種規(guī)定,規(guī)定一個(gè)范圍,表示你能夠傳哪些參數(shù)。 一個(gè)泛型類名尖括號(hào)之內(nèi)僅含有一個(gè)?
,就會(huì)限制這個(gè)泛型類傳入的類型為Object
,相當(dāng)于沒有限制,但是獲取元素時(shí)由于不能確定具體類型,只能使用Object
引用接收,所以<?>
也被稱為無(wú)界通配符。
//使用泛型打印順序表 public static<T> void printList1(ArrayList<T> list) { for (T x:list) { System.out.println(x); } } //使用通配符打印順序表 public static void printList2(ArrayList<?> list) { for (Object x:list) { System.out.println(x); } }
使用泛型T
能夠確定傳入的類型就是T
類型,所以使用T
類型的變量接收,而通配符?
沒有設(shè)置邊界的情況下,默認(rèn)上界是Object
沒有下界,為了保證安全,只能使用Object
類型的變量接收。
通配符是用來(lái)解決泛型無(wú)法協(xié)變的問(wèn)題的,協(xié)變指的就是如果Student
是Person
的子類,那么List<Student>
也應(yīng)該是List<Person>
的子類。但是泛型是不支持這樣的父子類關(guān)系的。
通配符也有上界,可以限制傳入的類型必須是上界這個(gè)類或者是這個(gè)類的子類。
基本語(yǔ)法:
<? extends 上界>
<? extends Number>//可以傳入的實(shí)參類型是Number或者Number的子類
例如:
public static void printAll(ArrayList<? extends Number> list) { for (Number n: list) { System.out.println(n); } }
我們對(duì)printAll
方法的一個(gè)形參限制了類型的上界Number
,所以在遍歷這個(gè)順序表的時(shí)候,需要使用Number
來(lái)接收順序表中的對(duì)象,并且使用該方法時(shí),只能遍歷輸出Number
及其子類的對(duì)象。
public static void main(String[] args) { printAll(new ArrayList<Integer>());//ok printAll(new ArrayList<Double>());//ok printAll(new ArrayList<Float>());//ok printAll(new ArrayList<String>());//error }
假設(shè)有如下幾個(gè)類:
class Animal{} class Cat extends Animal{} class Dog extends Animal{} class Bird extends Animal{}
Animal
是Cat
,Dog
,Bird
類的父類,我們來(lái)看一看使用泛型和使用通配符在打印對(duì)象結(jié)果上會(huì)有什么區(qū)別?我們對(duì)這兩者都設(shè)置了上界,當(dāng)打印不同的對(duì)象時(shí),到底會(huì)調(diào)用誰(shuí)的toString
方法。
//泛型 public static <T extends Animal> void printAnimal1(ArrayList<T> list) { for (T animal: list) { System.out.println(animal); } } //通配符 public static void printAnimal2(ArrayList<? extends Animal> list) { for (Animal animal: list) { System.out.println(animal); } }
我們先來(lái)看泛型,使用泛型指定類型后,那么指定什么類型,那它就會(huì)輸出什么類型的對(duì)象,比如你指定順序表中放的類型是Cat
,那么它調(diào)用的就是Cat
對(duì)象的toString
方法。
public static void main(String[] args) { Cat cat = new Cat(); Dog dog = new Dog(); Bird bird = new Bird(); //泛型 ArrayList<Cat> list1 = new ArrayList<>(); ArrayList<Dog> list2 = new ArrayList<>(); ArrayList<Bird> list3 = new ArrayList<>(); list1.add(cat); list2.add(dog); list3.add(bird); printAnimal1(list1);//Cat printAnimal1(list2);//Dog printAnimal1(list3);//Bird }
再來(lái)看一看通配符,使用通配符是規(guī)定能夠使用Animal
及其子類,不倫你傳入哪一個(gè)子類對(duì)象,都是父類的引用接收,但是具體哪一個(gè)子類,并不清楚。
public static void main(String[] args) { Cat cat = new Cat(); Dog dog = new Dog(); Bird bird = new Bird(); //通配符 ArrayList<Cat> list1 = new ArrayList<>(); ArrayList<Dog> list2 = new ArrayList<>(); ArrayList<Bird> list3 = new ArrayList<>(); list1.add(cat); list2.add(dog); list3.add(bird); printAnimal2(list1);//Cat printAnimal2(list2);//Dog printAnimal2(list3);//Bird }
父類引用接收子類對(duì)象發(fā)生了向上轉(zhuǎn)型,當(dāng)打印父類引用的子類對(duì)象時(shí),會(huì)優(yōu)先使用子類的toString
方法,在介紹多態(tài)的時(shí)候也講過(guò)這個(gè)問(wèn)題,所以輸出結(jié)果與使用泛型是一樣的,但是泛型和通配符的效果是不一樣的,泛型是你傳入什么類型,那這個(gè)類就會(huì)持有什么類型的對(duì)象,而通配符是規(guī)定一個(gè)范圍,規(guī)定你能夠傳哪一些類型。
通配符的上界是支持如下的父子類關(guān)系的,而泛型的上界不支持:
MyArrayList<? extends Number> 是 MyArrayList <Integer>或者 MyArrayList<Double>的父類類型
MyArrayList<?> 是 MyArrayList<? extends Number> 的父類型
對(duì)于通配符的上界有個(gè)特點(diǎn),先說(shuō)結(jié)論,使用通配符上界可以讀取數(shù)據(jù),但是并不適合寫入數(shù)據(jù),因?yàn)椴荒艽_定類所持有的對(duì)象具體是什么。
public static void main(String[] args) { ArrayList<Integer> arrayList1 = new ArrayList<>(); ArrayList<Double> arrayList2 = new ArrayList<>(); arrayList1.add(10); List<? extends Number> list = arrayList1; System.out.println(list.get(0));//ok Integer = list.get(0);//error因?yàn)椴荒艽_定list所持有的對(duì)象具體是什么 list.add(2);//error因?yàn)椴荒艽_定list所持有的對(duì)象具體是什么,為了安全,這種情況Java不允許插入元素 }
因?yàn)閺?code>list獲取的對(duì)象類型一定Number
或者Number
的子類,所以可以使用Number
引用來(lái)獲取元素,但是插入元素時(shí)你并不能確定它到底是哪一種類型,為了安全,使用通配符上界的list
不允許插入元素。
與泛型不同,通配符可以擁有下界,語(yǔ)法層面上與通配符的上界的區(qū)別是講關(guān)鍵字extends
改為super
。
<? super 下界>
<? super Integer>//代表 可以傳入的實(shí)參的類型是Integer或者Integer的父類類型
既然是下界那么通配符下界與上界對(duì)傳入類的規(guī)定是相反的,即規(guī)定一個(gè)泛型類只能傳入下界的這個(gè)類類型或者這個(gè)類的父類類型。比如<? super Integer>
代表 可以傳入的實(shí)參的類型是Integer
或者Integer
的父類類型(如Number
,Object
)
public static void printAll(ArrayList<? super Number> list) { for (Object n: list) { //此處只能使用Object接收,因?yàn)閭魅氲念愂荖umber或者是Number的父類 System.out.println(n); } }
public static void main(String[] args) { printAll(new ArrayList<Number>());//ok printAll(new ArrayList<Object>());//ok printAll(new ArrayList<Double>());//error printAll(new ArrayList<String>());//error printAll(new ArrayList<Integer>());//error }
同理通配符的下界也是滿足像下面這種父子類關(guān)系的。
MyArrayList<? super Integer> 是 MyArrayList<Integer>的父類類型
MyArrayList<?> 是 MyArrayList<? super Integer>的父類類型
總結(jié): ?
是? extends ....
和? super ....
的父類,看通配符之間的父子類關(guān)系,最關(guān)鍵的是看通配符所“規(guī)定的”范圍,判斷父子類是根據(jù)這個(gè)范圍來(lái)判斷的。
通配符的下界也有一個(gè)特點(diǎn),那就是它能夠允許寫入數(shù)據(jù),當(dāng)然能夠?qū)懭氲臄?shù)據(jù)對(duì)象是下界以及下界的子類,但是并不擅長(zhǎng)讀數(shù)據(jù),與通配符的上界相反。
public static void main(String[] args) { ArrayList<? super Animal> list = new ArrayList<Animal>(); ArrayList<? super Animal> list2 = new ArrayList<Cat>();//編譯報(bào)錯(cuò),list2只能引用Animal或者Animal父類類型的list list.add(new Animal());//添加元素時(shí),只要添加的元素的類型是Animal或者Animal的子類就可以 list.add(new Cat()); Object s2 = list.get(0);//可以 ArrayList<? super Animal> list3 = new ArrayList<Object>(); Cat s1 = list3.get(0);//error因?yàn)闃?gòu)造對(duì)象時(shí)可以構(gòu)造Animal父類類型的ArrayList,取出的對(duì)象不一定是Animal或者Animal的子類 }
對(duì)于這個(gè)栗子添加元素時(shí),只要添加的元素的類型是Animal或者Animal的子類就可以,獲取元素時(shí),只能使用Object
引用接收,不能使用其他的引用接收,因?yàn)橐驗(yàn)闃?gòu)造對(duì)象時(shí)可以構(gòu)造Animal父類類型的ArrayList,雖然可以插入Animal以及其子類對(duì)象,但取出的對(duì)象不能保證是Animal或者Animal的子類。
以上是“Java中泛型與通配符的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。