国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

泛型之通配符

PingCAP / 2370人閱讀

摘要:調(diào)用相當(dāng)于通過(guò)使用通配符,可以傳遞任何類型的對(duì)象,但也是有缺點(diǎn)的。使用通配符,賦值傳值的時(shí)候方便了,但是對(duì)泛型類中參數(shù)為泛型的方法起到了副作用。結(jié)論當(dāng)使用父界限定通配符時(shí),泛型類中返回值為泛型的方法不能使用。

數(shù)組 VS List

第一回合
數(shù)組類型為Object,可以存儲(chǔ)任意類型的對(duì)象,List集合同樣可以做到

Object[] obj = new Object[1];
List list = new ArrayList();

第二回合
數(shù)組類型可以為Integer類型,專門存儲(chǔ)Integer類型對(duì)象,List集合同樣也可以

Integer[] integer = new Integer[1];
List list = new ArrayList<>();

決勝局
前兩局雙方打成平手,最后的決勝局。先看數(shù)組代碼:

Object[] obj = new Integer[2];
obj[0] = 52021;
//編譯期OK,運(yùn)行期就掛了
obj[1] = "Full of confidence";

上面的代碼在運(yùn)行期會(huì)拋出異常:java.lang.ArrayStoreException: java.lang.String

List集合代碼:

//編譯期報(bào)錯(cuò)
List obj = new ArrayList();

最終結(jié)果,List集合更勝一籌,因?yàn)樗鼙M早的發(fā)現(xiàn)錯(cuò)誤。

分析最后一戰(zhàn)中數(shù)組的代碼:

在編譯期間,編譯器不會(huì)檢查這樣的賦值,編譯器覺(jué)得它是合理的,因?yàn)楦割愐弥赶蜃宇悓?duì)象,沒(méi)有任何問(wèn)題。賦值時(shí),將字符串存儲(chǔ)在一個(gè)Object類型的數(shù)組中也說(shuō)的過(guò)去,但在運(yùn)行時(shí),發(fā)現(xiàn)明明內(nèi)存分配的是存儲(chǔ)整型類型對(duì)象的格子,里面卻放著字符串類型的對(duì)象,自然會(huì)報(bào)錯(cuò)了。

分析最后一戰(zhàn)中List集合的代碼:

由于運(yùn)用了泛型,在編譯期就發(fā)現(xiàn)了錯(cuò)誤,避免了將問(wèn)題帶到運(yùn)行時(shí)。
思考個(gè)問(wèn)題,如果代碼在編譯期沒(méi)有報(bào)錯(cuò)會(huì)發(fā)生什么?

在編譯期沒(méi)有報(bào)錯(cuò)并且在運(yùn)行期會(huì)將泛型擦除,全部變?yōu)榱薕bject類型。所以執(zhí)行obj.add(new Integer(1))也是可以的。如果真是這樣的話,那么泛型還有什么存在的意義呢?所以這種假設(shè)是不存在的,所以會(huì)在編譯期報(bào)錯(cuò)。編譯期報(bào)錯(cuò)的原因就是在使用泛型時(shí),泛型的引用和創(chuàng)建兩端,給出的泛型變量不相同,所以在使用泛型時(shí),泛型的引用和創(chuàng)建兩端,給出的泛型變量必須相同。

通配符

通配符只能出現(xiàn)在等號(hào)左面,不能出現(xiàn)在new的一邊。

List list = new ArrayList()

List obj1 = new ArrayList()

List obj = new ArrayList()

無(wú)界通配符
public void foo() {
    List list = new ArrayList();
    //foo2(list); //編譯期報(bào)錯(cuò)
    foo3(list); //正常編譯
}

public void foo2(List list) {//TODO}
public void foo3(List list){//TODO}

上面代碼中,調(diào)用foo2方法編譯期報(bào)錯(cuò)原因:泛型的引用和創(chuàng)建兩端,給出的泛型變量不一致,相當(dāng)于:List list = new ArrayList();

public void foo() {
    List list = new ArrayList();
    List strList = new ArrayList();
    foo3(list); //正常編譯
}
public void foo3(List list) {
    //TODO
}

現(xiàn)在希望將strList作為參數(shù)調(diào)用foo3方法,這時(shí)就想到了方法的重載,所以定義了一個(gè)重載的方法。public void foo3(List list){//TODO}
定義完成后,竟然報(bào)錯(cuò)了,并且foo3(List list)也報(bào)錯(cuò)了。這是由于泛型擦除導(dǎo)致的。在運(yùn)行期,會(huì)有泛型擦除,所以foo3(List list)foo3(List list)會(huì)變成一樣的方法,所以在編譯期就要報(bào)錯(cuò),否則在運(yùn)行期就無(wú)法區(qū)分了。

這里無(wú)法使用foo3方法重載,除非定義不同名字的方法。除了定義不同名字的方法之外,還可以使用通配符。

public void foo() {
    List list = new ArrayList();
    List strList = new ArrayList();
    foo3(list);
    foo3(strList);
}
public void foo3(List list) {
    //TODO
}

調(diào)用foo3(strList);相當(dāng)于:
List list = new ArrayList(); => List list = strList

通過(guò)使用通配符,foo3(List list);可以傳遞任何類型的對(duì)象,但也是有缺點(diǎn)的。使用通配符,賦值/傳值的時(shí)候方便了,但是對(duì)泛型類中參數(shù)為泛型的方法起到了副作用。如何理解泛型類中參數(shù)為泛型的方法起到了副作用這句話呢?結(jié)合代碼來(lái)看

/**
 * 使用 ? 通配符
 */
public void foo3(List list) {
    //list.add(1); //編譯期報(bào)錯(cuò),起到了副作用
    //list.add("hello"); //編譯期報(bào)錯(cuò),起到了副作用
    Object o = list.get(0); //其實(shí)也是作廢的,只是由于Object是所有類的父類,所以這里不會(huì)報(bào)錯(cuò)。
}

List定義:接口ListE代表是泛型類;List中add方法定義:boolean add(E e),參數(shù)為E,說(shuō)明參數(shù)為泛型。List接口使用通配符,調(diào)用add方法時(shí),副作用是在編譯期報(bào)錯(cuò);泛型類中返回值為泛型的方法,也作廢了,如:get方法定義:E get(int index)

子界限定

子界限定:? extends Number

解釋:? 是 Number 類型或者是 Number 的子類型

缺點(diǎn):參數(shù)為泛型的方法不能使用

public void foo4() {
    List intList = new ArrayList();
    List longList = new ArrayList();
    foo5(intList); //Integer是Number的子類型
    foo5(longList); //Long是Number的子類型
}
public void foo5(List list) {
    //list.add(1); //編譯期報(bào)錯(cuò)
    //list.add(2L); //編譯期報(bào)錯(cuò)
}

分析以上代碼:

foo5(intList);相當(dāng)于List list = intList;賦值操作,這是沒(méi)有問(wèn)題的;list.add(1);則會(huì)在編譯期報(bào)錯(cuò)。
list定義的類型是List,它帶有泛型,而add方法的參數(shù)也是泛型類型,符合:泛型類中參數(shù)為泛型的方法起到了副作用這個(gè)結(jié)論。所以調(diào)用add編譯期報(bào)錯(cuò)。

想想看,如果list.add(1);不報(bào)錯(cuò):

foo4中調(diào)用了foo5(longList);相當(dāng)于List list = new ArrayList();,然后執(zhí)行foo5,調(diào)用list.add(1);如果不報(bào)錯(cuò)也就相當(dāng)于Long類型容器可以盛放Integer類型數(shù)據(jù),這樣一來(lái),泛型也就沒(méi)有意義了。有人也許會(huì)問(wèn),既然add方法會(huì)報(bào)錯(cuò),為什么foo5(longList);沒(méi)有問(wèn)題?其實(shí)我覺(jué)得這是不一樣的,調(diào)用add方法不確定因素很多,因?yàn)轭愋涂赡苁荌nteger,也可能是Long,人們無(wú)法保證在調(diào)用add方法時(shí),只傳遞相同類型的變量,所以程序就直接限定死了,你不可以add任何東西。但直接賦值,這個(gè)值是可以確定的,類型具有統(tǒng)一性,要是什么都是什么,所以是可行的。

結(jié)論:當(dāng)使用子界限定通配符時(shí),泛型類中參數(shù)為泛型的方法不能使用

也許有人會(huì)問(wèn),這樣做是否可以確定類型?

List list = new ArrayList();
list.add(1); //編譯期報(bào)錯(cuò)

很遺憾,這樣也是不行的。? 仍然代表了不確定性,所以編譯器壓根就是將這種方式的方法的參數(shù)類型是泛型的全部廢掉了。

add不能用,那賦值操作后可從中取值嗎?答案是肯定的。
Number number = list.get(0);

分析以上代碼:

無(wú)論返回什么值,總歸都是Number類型的,這是可以確定的,所以可以用Number接收返回值為泛型的方法。當(dāng)然,這里說(shuō)沒(méi)有問(wèn)題也只能是Number類型或者是Object類型接收,別的類型是不可以的。

結(jié)論:當(dāng)使用子界限定通配符時(shí),泛型類中返回值為泛型的方法可以使用

父界限定

父界限定:? super Integer

解釋:? 是Integer類型或者是Integer的父類型

缺點(diǎn):返回值為泛型的方法不能使用

public void foo6() {
    List numList = new ArrayList();
    List intList = new ArrayList();
    foo7(numList); //Number是Integer的父類型
    foo7(intList); //Integer是本身
}
public void foo7(List list) {
    list.add(1);
}

分析以上代碼:

list.add(1);不會(huì)報(bào)錯(cuò),因?yàn)轭愋涂梢源_定。

如果List list的賦值是List list = new ArrayList();沒(méi)問(wèn)題

如果List list的賦值是List list = new ArrayList();沒(méi)問(wèn)題

如果List list的賦值是List list = new ArrayList();也沒(méi)問(wèn)題

所以只要add(1)就肯定沒(méi)有問(wèn)題,就是說(shuō)add(1),這個(gè)實(shí)參1,符合任何一種情況。

結(jié)論:當(dāng)使用父界限定通配符時(shí),泛型類中參數(shù)為泛型的方法可以使用

public void foo7(List list) {
    list.add(1);
    Object obj = list.get(0);
}

Object obj = list.get(0);這句話沒(méi)有報(bào)錯(cuò),但其實(shí)是作廢的,只是由于Object是所有類的父類,所以才可以這么用。

結(jié)論:當(dāng)使用父界限定通配符時(shí),泛型類中返回值為泛型的方法不能使用

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/73385.html

相關(guān)文章

  • Java 型之上界下界配符

    摘要:泛型之上界下界通配符本教程是為編寫的。這是在使用泛型編程時(shí)一個(gè)常見(jiàn)的誤解,也是一個(gè)需要學(xué)習(xí)的重要概念。通配符使用指南學(xué)習(xí)使用泛型編程時(shí),更令人困惑的一個(gè)方面是確定何時(shí)使用上限有界通配符以及何時(shí)使用下限有界通配符。 Java 泛型之上界下界通配符 本Java教程是為JDK 8編寫的。本頁(yè)描述的示例和實(shí)踐沒(méi)有利用后續(xù)版本中引入的改進(jìn)。 泛型,繼承和子類 如你所知,只要類型兼容,就可以將一種...

    shiyang6017 評(píng)論0 收藏0
  • 型之泛型

    摘要:定義具有一個(gè)或多個(gè)類型變量的類,稱之為泛型類。泛型類的繼承創(chuàng)建對(duì)象的兩種方式錯(cuò)誤方式錯(cuò)誤原因繼承了泛型類,但并不是泛型類,所以不能這樣創(chuàng)建對(duì)象。同樣是泛型類,它的父類也是泛型類,它傳遞的是常量。 泛型類 public class A { //在成員變量上使用泛型 private T t; public A() {} //構(gòu)造參數(shù)類型上...

    caoym 評(píng)論0 收藏0
  • 型之泛型方法

    摘要:泛型方法顯式賦值張三李四王五隱式賦值,常用此方式,可以不指定張三李四王五泛型方法不受類的限制,也就是說(shuō),即使方法所在的類不是泛型類,也可以定義泛型方法在泛型類中定義的方法,也不一定是泛型方法,就看你如何定義了。泛型類中可以定義泛型方法。 public class F { //泛型方法 public static T getT(T[] array...

    sydMobile 評(píng)論0 收藏0
  • 淺析Java泛型

    摘要:泛型類在類的申明時(shí)指定參數(shù),即構(gòu)成了泛型類。換句話說(shuō),泛型類可以看成普通類的工廠。的作用就是指明泛型的具體類型,而類型的變量,可以用來(lái)創(chuàng)建泛型類的對(duì)象。只有聲明了的方法才是泛型方法,泛型類中的使用了泛型的成員方法并不是泛型方法。 什么是泛型? 泛型是JDK 1.5的一項(xiàng)新特性,它的本質(zhì)是參數(shù)化類型(Parameterized Type)的應(yīng)用,也就是說(shuō)所操作的數(shù)據(jù)類型被指定為一個(gè)參數(shù),...

    godiscoder 評(píng)論0 收藏0
  • JAVA泛型筆記

    摘要:泛型類泛型類和普通類的區(qū)別就是類定義時(shí),在類名后加上泛型聲明。泛型類的內(nèi)部成員方法就可以使用聲明的參數(shù)類型。 泛型是JDK 1.5的一項(xiàng)新特性,它的本質(zhì)是參數(shù)化類型(Parameterized Type),即所操作的數(shù)據(jù)類型在定義時(shí)被指定為一個(gè)參數(shù)。當(dāng)我們使用的時(shí)候給這個(gè)參數(shù)指定不同的對(duì)象類型,就可以處理不同的對(duì)象。這種參數(shù)類型可以用在類、接口和方法的創(chuàng)建中,分別稱為泛型類、泛型接口和...

    n7then 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

閱讀需要支付1元查看
<