日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

[转载] JAVA泛型杂谈--擦除,协变,逆变,通配符等

發(fā)布時間:2025/3/11 编程问答 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [转载] JAVA泛型杂谈--擦除,协变,逆变,通配符等 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

參考鏈接: Java中的協(xié)變返回類型

在《JAVA核心思想》這本書里,關(guān)于泛型的章節(jié)意外的很多,小小的泛型里其實有很多可以學(xué)習(xí)的內(nèi)容,我總結(jié)下最近看書的成果。?

一. 泛型的好處和應(yīng)用?

最基礎(chǔ)的用到泛型的地方無非是在容器里 使用泛型用以保證容器內(nèi)數(shù)據(jù)的類型統(tǒng)一,所以我們先總結(jié)下泛型使用的好處:?

可以統(tǒng)一集合類型容器的存儲類型,防止在運行期出現(xiàn)類型裝換異常,增加編譯時類型的檢查解決重復(fù)代碼的編寫,能夠復(fù)用算法。可以起到重載的作用?

第二個作用很好理解,泛型 的 ‘泛’ 即代表著 ‘泛化’,不僅僅是保證容器的安全性,更重要的是減少類型的限制,讓我們編寫更加通用的代碼。我們舉個例子:? 在javaweb中,我們經(jīng)常向前臺返回JSON對象信息,不同的業(yè)務(wù)可以會組裝不同的bean,為了節(jié)省提高代碼的復(fù)用性,我們可以這么寫一個類:?

public class ReturnObject<A, B> {

?

? ? public final A a;

? ? public final B b;

?

? ? public ReturnObject(A a, B b) {

? ? ? ? this.a = a;

? ? ? ? this.b = b;

? ? }

?

? ? public <A> A t(A a) {

? ? ? ? return a;

? ? }

?

? ? @Override

? ? public String toString() {

? ? ? ? return "ReturnObject{" +

? ? ? ? ? ? ? ? "a=" + a +

? ? ? ? ? ? ? ? ", b=" + b +

? ? ? ? ? ? ? ? '}';

? ? }

}?

這個類沒有具體的類型,意思也很簡單,就是不限定變量的類型,根據(jù)你業(yè)務(wù)的不同,你可以傳不同的類型進去(通過構(gòu)造器),更方便的是,java泛型支持繼承,你可以隨意拓展你的業(yè)務(wù)字段,也就不再需要為了一種業(yè)務(wù)專門創(chuàng)建一個bean類了。?

// 業(yè)務(wù)字段拓展

public class ReturnObjectExtender<A, B, C> extends ReturnObject<A, B> {

?

? ? public final C c;

?

? ? public ReturnObjectExtender(A a, B b, C c) {

? ? ? ? super(a, b);

? ? ? ? this.c = c;

? ? }

?

? ? @Override

? ? public String toString() {

? ? ? ? return "ReturnObjectExtender{" +

? ? ? ? ? ? ? ? "c=" + c +

? ? ? ? ? ? ? ? ", a=" + a +

? ? ? ? ? ? ? ? ", b=" + b +

? ? ? ? ? ? ? ? '}';

? ? }

}?

二. 重要!泛型的擦除?

JAVA的泛型都是通過擦除來實現(xiàn)的,這句話的意思是 當(dāng)你的程序真正跑起來的時候,任何具體的類型其實都已經(jīng)被擦除了,所以在下面的例子中,輸出的結(jié)果是true,aClass和aClass1都是一樣的class生成的對象。?

Class aClass = new ArrayList<Integer>().getClass();

Class aClass1 = new ArrayList<String>().getClass();

?

System.out.println(aClass == aClass1);

?

擦除的負面效應(yīng)直接體現(xiàn)在如果你寫下面這段代碼,T類型并不能認出你傳給它的是String類型,T直接會被Object替代,?

public class WildCardTest<T> {

?

? ? public void f(T t) {

? ? //這一段編譯報錯

? ? ? ? t.isEmpty();

? ? }

?

? ? public static void main(String[] args) {

? ? ? ? WildCardTest<String> stringWildCardTest = new WildCardTest<>();

? ? ? ? stringWildCardTest.f("");

? ? }

}?

要讓String調(diào)用它的isEmpty()方法,需要給泛型一個邊界,代碼只需要重新改一下,T extends String表明T可以是String類或是String的子類,如果傳入的沒有問題,那就可以調(diào)用isEmpty()方法。?

public class WildCardTest<T extends String> {

?

? ? public void f(T t) {

? ? ? ? t.isEmpty();

? ? }

?

? ? public static void main(String[] args) {

? ? ? ? WildCardTest<String> stringWildCardTest = new WildCardTest<>();

? ? ? ? stringWildCardTest.f("");

? ? }

}?

擦除是歷史遺留問題?

java的泛型不是從jdk1.0就出現(xiàn)的,為了跟以往沒有泛型代碼的源代碼兼容,例如List被擦除為List,而普通的類型變量在未指定邊界的時候被擦除為Object,從而實現(xiàn)泛型的功能并且向后兼容。?

三. 泛型的通配符(逆變與協(xié)變)?

這是兩個賦值,一個是數(shù)組,ArrayList因為是Collection的子類,所以數(shù)組向上轉(zhuǎn)型是可以的;另一個是帶泛型的ArrayList,帶ArrayList的泛型并不能賦值給帶Collection的泛型。?

Collection[] collections = new ArrayList[]{};

//泛型會報錯

ArrayList<Collection> collections1 = new ArrayList<ArrayList>();?

逆變,協(xié)變與不變?

為什么會導(dǎo)致這樣的差異呢?這里又引出了一個概念– 逆變,協(xié)變與不變。逆變與協(xié)變用來描述類型轉(zhuǎn)換后的繼承關(guān)系。?

f(?)是逆變(contravariant)的,當(dāng)A≤B時有f(B)≤f(A)成立;

f(?)是協(xié)變(covariant)的,當(dāng)A≤B時有成立f(A)≤f(B)成立;

f(?)是不變(invariant)的,當(dāng)A≤B時上述兩個式子均不成立,即f(A)與f(B)相互之間沒有繼承關(guān)系。?

根據(jù)上面兩個賦值語句做解釋,A 是ArrayList ,B是Collection,所以B > A,這個沒有問題,然后 A[] 數(shù)組當(dāng)作f(A),B[] 數(shù)組當(dāng)作f(B),并且A[]可以賦值給B[]數(shù)組,說明 f(B) >=f(A),符合協(xié)變原則,所以數(shù)組是協(xié)變的。? 而泛型也套用這個規(guī)則,發(fā)現(xiàn) 泛型其實是不變的。?

Java中泛型是不變的,可有時需要實現(xiàn)逆變與協(xié)變,怎么辦呢?這時,通配符?派上了用場:?

// <? extends>實現(xiàn)了泛型的協(xié)變,它意味著某種Collection或Collection子類的類型,規(guī)定了該容器持有類型的上限,它是具體的類型,只是這個類型是什么沒有人關(guān)心? 比如:

List<? extends Collection> list = new ArrayList<ArrayList>();

?

// <? super>實現(xiàn)了泛型的逆變,它意味著某種ArrayList或ArrayList父類的類型,規(guī)定了該容器持有類型的下限,比如:

List<? super ArrayList> list = new ArrayList<Collection>();??

逆變,協(xié)變的應(yīng)用?

在協(xié)變中,還是先以數(shù)組做舉例,協(xié)變中對持有對象的存入有嚴(yán)格限制:?

Collection[] collections = new ArrayList[2];

?

collections[0] = new ArrayList();

//這一步編譯沒問題。但是運行時發(fā)現(xiàn)數(shù)組里已經(jīng)定好了只能存ArrayList類型,所以會拋ArrayStoreException

collections[1] = new LinkedList();?

所以在泛型的協(xié)變中,例如ArrayList的add方法是不能調(diào)用了,在編譯期間直接報錯。?

這是ArrayList 的add,get方法定義,當(dāng)使用協(xié)變時,E e 會被直接替換成 ? extends E?

public boolean add(E e);

public E get(int index);?

具體事例:?

ArrayList<? extends Set> sets = new HashSet<>();

?

//因為 ? extends Set 編譯器不知道sets引用指向什么對象,有可能是 HashSet,可能是TreeSet,這種不確定性導(dǎo)致sets不能使用add方法。

//sets.add(new HashSet());

?

//能插入null值

sets.add(null);

?

//因為這個泛型參數(shù)的上限是Set,為了安全性,所以只返回set類型

Set set = sets.get(0);?

在逆變中,因為規(guī)定了泛型的下界,所以get set 方法的使用限制又有所不同:?

ArrayList<? super List> list = new ArrayList<Collection>();

?

//對于 add方法,只能放List或List的子類,因為list容器泛型參數(shù)都是List的父類 不會出現(xiàn)問題

list.add(new ArrayList());

//不能add HashSet

//list.add(new HashSet());

//不能add Object

//list.add(new Object());

?

//因為這個泛型參數(shù)的下限是List? ? 所以無法確定這是個什么類型,只能返回Object

Object object = list.get(0);?

無界通配符?

除了extends和super,還有一種 List<\?>這種通配符,代表著任何事物,但它與List不同的是:?

List<\Object> = List = ‘持有任何Object類型的原生List’List<\?>表示–’具有某種特定類型的非原生List,只是我們不知道那種類型是什么’。?

具體用代碼看出區(qū)別:?

ArrayList<Collection> collections2 = new ArrayList<>();

?

ArrayList<?> objects = new ArrayList<>();

//?代表持有某種特定類型 ,所以也可以是Collection,這種賦值時合法的

objects = collections2;

?

//?代表持有某種特定類型,d但是不確定具體哪種,所以只能返回Object

Object o = objects.get(0);

?

//?代表持有某種特定類型,但是什么類型編譯器并不知道,所以為了安全起見,不會讓你用add方法

//objects.add(new Object());

?

?

//可以add null

objects.add(null);

?

總結(jié)來說:?

要從泛型類取數(shù)據(jù)時,用extends;要往泛型類寫數(shù)據(jù)時,用super;既要取又要寫,就不用通配符(即extends與super都不用)。?

四. 總結(jié)?

這篇文章總結(jié)的是書里比較重要的知識點,跳過了簡單的應(yīng)用,寫了那么多,感覺總結(jié)還是很有必要的,你第一遍看書也許概念會有些懵懂,但是再記錄總結(jié)下,你會解開第一遍看書時有點么棱兩可的知識點。

總結(jié)

以上是生活随笔為你收集整理的[转载] JAVA泛型杂谈--擦除,协变,逆变,通配符等的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 女同动漫免费观看高清完整版在线观看 | 欧美体内she精高潮 日韩一区免费 | 在线五月天 | 成人v精品蜜桃久一区 | 91视频 - 88av | 国产成人精品一区二三区四区五区 | 亚洲第一激情 | 国产在线视频福利 | 国产一伦一伦一伦 | 色狠av | 特级西西人体444www高清 | 男同av在线观看一区二区三区 | 丰满大乳露双乳呻吟 | 亚洲精品另类 | 爱福利视频一区二区 | 伊人66| 久久青草热 | 国产午夜福利精品 | 日韩精品电影在线观看 | 特黄aaaaaaaaa毛片免 | wwwwww国产 | 99热一区二区 | 天堂网中文在线观看 | 亚洲第一精品网站 | 激情五月婷婷小说 | 亚洲第一字幕 | 午夜一区二区三区免费 | 好吊色视频在线观看 | 看全黄大色黄大片 | 国产成人精品亚洲 | 国产特黄毛片 | 日韩在线一区视频 | 日韩a级片 | 浪漫樱花在线观看高清动漫 | 91精品国产自产精品男人的天堂 | 一级片视频免费看 | 成人免费看片在线观看 | 97人妻精品一区二区三区动漫 | 99re6热在线精品视频播放 | 久久国产精品波多野结衣 | 奇米影视在线 | 禁漫天堂免费网站 | 欧美在线 | 国产黄| 一区二区三区激情视频 | 天天综合精品 | 亚洲丝袜色图 | 日韩av男人的天堂 | 国产91黄色 | 亚洲热影院 | 天天插日日干 | 亚洲欧美日韩一区在线观看 | 国产精品欧美激情在线播放 | 色伊伊 | 日日干夜夜干 | 色播亚洲 | 精品一区二区三区电影 | 精品一区中文字幕 | 欧美性jizz18性欧美 | 日本高清不卡视频 | 亚洲国产毛片aaaaa无费看 | 久久免费视频2 | 国产吃瓜黑料一区二区 | 一级免费黄色大片 | 夜夜草影院| 国产精品毛片一区视频播 | 国产成人精品白浆久久69 | 少妇人妻邻居 | 九九色网站| 成长快手短视频在线观看 | 亚洲视频久久久 | 孕妇毛片 | 免费看a的网站 | 久草影视网 | 欧美成人毛片 | 黄色在线观看国产 | 欧美福利网 | 日韩免费观看一区二区 | 日本高清不卡视频 | 色噜噜在线 | 一级少妇片 | 国精产品99永久一区一区 | 亚欧精品在线观看 | 国产黄色片在线播放 | 波多野结衣在线播放视频 | 日韩欧美一级二级 | 中文无码精品一区二区三区 | 国产一级免费观看 | 狠狠操av| 苍井空浴缸大战猛男120分钟 | 精品人妻一区二区三区久久 | 日本中文字幕精品 | www在线看片 | 久草福利 | 少妇av一区二区三区 | 久久久久久无码午夜精品直播 | 国产污视频在线看 | 日本不卡一区在线观看 | 操亚洲女人 |