成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

Java泛型中的通配符

sunny5541 / 1222人閱讀

摘要:好了,有了這樣的背景知識(shí),我們可以來看一下上界通配了,在中,可以使用來界定一個(gè)上界,的意思是所有屬于的子類,是上界,不能突破天界啊,我們具體化一下,的意思就是,所有的子類都可以匹配這個(gè)通配符。

1、上界通配符

首先,需要知道的是,Java語言中的數(shù)組是支付協(xié)變的,什么意思呢?看下面的代碼:

    static class A extends Base{
        void f() {
            System.out.println("A.f");
        }
    }

    static class B extends A {
        void f() {
            System.out.println("B.f");
        }
    }

    static class C extends B {
        void f() {
            System.out.println("C.f");
        }
    }

    static {

        A[] arrayA = new A[3];

        arrayA[0] = new A();
        arrayA[1] = new B();
        arrayA[2] = new C();

        for (A item : arrayA) {
            item.f();
        }
        
    } 

//output
A.f
B.f
C.f

我們明明讓數(shù)組的類型為A,但是向其中加入B、C也是可以行得通的,為什么呢?我們發(fā)現(xiàn)B繼承了A,屬于A的子類,C繼承了B,屬于B的子類,Java中的繼承是可以傳遞的,所以C依然屬于A的子類,所以B和C都是A的子類,另外一點(diǎn),在Java中,類型向上轉(zhuǎn)換是非常自然的,不需要強(qiáng)制轉(zhuǎn)換會(huì)自動(dòng)進(jìn)行,也就是說,B和C的實(shí)例都可以自動(dòng)轉(zhuǎn)換為類型A的實(shí)例。好了,有了這樣的背景知識(shí),我們可以來看一下上界通配了,在java中,可以使用 來界定一個(gè)上界,的意思是所有屬于Type的子類,Type是上界,不能突破天界啊,我們具體化一下,的意思就是,所有A的子類都可以匹配這個(gè)通配符。所有我們的B、C的實(shí)例以及他們的子類的實(shí)例都可以匹配,但是Base就不可以,因?yàn)锽ase是A的父類,而我們的上界是A啊,所以當(dāng)然不能是Base了。很自然的,我們有下面的代碼:

        A a = new B();
        A b = new C();
        C c = new C();

       List list = new ArrayList();
    
      list.add(a);
      list.add(b);
      list.add(c);

我們覺得很自然這樣做是無可厚非的,對(duì)吧?但是編譯器很顯然不允許我們這樣做,為什么?我們的list的類型使用了上界通配符啊,而且匹配的是所有A的子類,而我們add的都是A的子類啊,為什么不可以呢?我們?cè)賮砜匆幌?? extends A>,我們的list可以持有任何A的子類對(duì)象,也就是A、B、C的實(shí)例都是可以的,那我們是不是可以把認(rèn)為是的子類呢?呢?我們暫且認(rèn)為是可以這樣吧,那看下面的這個(gè)方法:

    void joke(List list) {
        A a = new B();
        A b = new C();
        C c = new C();
        
        list.add(a);
        list.add(b);
        list.add(c);
    }

當(dāng)然上面的代碼是無法通過編譯的,我們分析一下為什么,記住是設(shè)定上界,所以,joke方法的參數(shù)是開放的,我們可以傳進(jìn)去一個(gè)的list,也可以是一個(gè)的list,還可以是一個(gè)的list。因?yàn)橄旅娴拇a是可以通過編譯的:

    private static void jokeIn(List list) {
        //
    }
    
    static {
        List list = new ArrayList<>();
        List list1 = new ArrayList<>();
        List list2 = new ArrayList<>();
        
        jokeIn(list);
        jokeIn(list1);
        jokeIn(list2);
    }

好吧,問題來了,當(dāng)我們傳到j(luò)oke方法中的參數(shù)是List的時(shí)候,方法內(nèi)部的add都是可以接受的,但是當(dāng)我們傳進(jìn)去的參數(shù)是List的時(shí)候,list.add(a)明顯是無法成功的,因?yàn)槲覀兊膌ist將可以允許持有B的子類,但是A不在這個(gè)范圍里面,所以是不合法的,當(dāng)傳進(jìn)去的是List的時(shí)候呢?連list.add(B)也不允許了。所以這就是問題所在,所以不允許這樣的代碼通過編譯是明智的,因?yàn)槲覀儾荒芸偸潜WC調(diào)用joke方法的用戶會(huì)嚴(yán)格傳進(jìn)來一個(gè)List的參數(shù)。
那怎么使用上界呢?換句話說,如何來產(chǎn)生一個(gè)List的list呢?還記得一開始我們說的數(shù)組協(xié)變嗎?下面的代碼使用了java語言數(shù)組具有協(xié)變能力來產(chǎn)生一個(gè)具有上界的list:

     List list = Arrays.asList(a, b);

Arrays.asList(T ... data)使用了ArrayList的一個(gè)構(gòu)造函數(shù):

        ArrayList(E[] array) {
            a = Objects.requireNonNull(array);
        }

可以看到使用了數(shù)組的協(xié)變,使得我們可以在Arrays.asList里面?zhèn)鬟f進(jìn)去所以A的子類對(duì)象。

2、下界通配符

上界定義了可以達(dá)到了最高點(diǎn),超出就是違法的;而下界則是說明了底線,你只能比底線更高級(jí),低于底線就是違法的。在java里面,可以使用來表達(dá)下界的意義,具體一點(diǎn),表達(dá)的和是兩個(gè)相反的方向,前者是說所有基于A的基類,后者是說所有基于A的子類,我們?cè)賮砜匆幌孪旅孢@個(gè)方法:

    void joke(List list) {
        A a = new B();
        A b = new C();
        C c = new C();
        
        list.add(a);
        list.add(b);
        list.add(c);
    }

此時(shí)的joke方法的參數(shù)是List,此時(shí)List和List都變成了List的父類了,因?yàn)閷?shí)際上List和List表達(dá)的能力比List更強(qiáng),也就是List包含了List和List,而List則包含了List,好了,說明了這些之后,我們?cè)賮砜匆幌聦?duì)joke方法的調(diào)用會(huì)出現(xiàn)哪些情況:

    static {
        List list = new ArrayList<>();
        List list1 = new ArrayList<>();
        List list2 = new ArrayList<>();
        
        jokeIn(list);
        jokeIn(list1); // error
        jokeIn(list2); //error
    }

好吧,問題出現(xiàn)了,我們可以將List 的參數(shù)傳遞給joke,因?yàn)檫@正是我們需要的,而我們也知道List的表達(dá)能力在List中是最低的,所以,當(dāng)我們將一個(gè)表達(dá)能力強(qiáng)于List的參數(shù)傳遞給joke之后,編譯器報(bào)錯(cuò)了。當(dāng)然,這僅僅是為了說明所謂下界的界定。

有了下界,我們可以使用下面的代碼來為我們工作了:

       List lists = new ArrayList<>();
        lists.add(a);
        lists.add(b);
        lists.add(c);

解釋一下,lists里面的元素類型是這樣一種類型,這種類型是A的基類,我們只是界定了下界,只要高于這個(gè)下界,就可以被lists接收,而b、c的基類都是A,可以被lists接收,所以上面的代碼是可以工作的。

3、無界通配符

有了上界和下界,還有無界,需要說明的一點(diǎn)是,不能同時(shí)使用上界和下界,因?yàn)橛袩o界啊(開玩笑的)??!
我們?cè)趈ava中使用來表達(dá)無界,對(duì)于,目前來講鎖表達(dá)的意思是:

我是想要java的范型來編寫這段代碼,我在這里并不是想使用原生類
型,但是在當(dāng)前這種情況下,泛型參數(shù)可以持有任何類型。

                     ----來自《java編程思想》15.10.3 無界通配符(686頁)

使用無界通配符的一種場(chǎng)景是:如果向一個(gè)使用的方法傳遞了一個(gè)原生類型,那么對(duì)編譯器來說可能會(huì)推斷出實(shí)際的參數(shù)類型,使得這個(gè)方法可以回轉(zhuǎn)并且調(diào)用另外一個(gè)使用這個(gè)確切類型的方法。這叫做“類型捕獲”,看下面的代碼:

    static class Holder {
        private T data;

        public Holder() {

        }

        public Holder(T data) {
            this.data =data;
        }

        public T getData() {
            return data;
        }

        public void setData(T data) {
            this.data = data;
        }
    }


    static  void actual(Holder holder) {
        System.out.println(holder.getData());
    }

    static void func(Holder holder) {
        actual(holder);
    }

    static {

        Holder holder = new Holder<>("hujian");

        func(holder);
        
    }

可以看到,actual的參數(shù)是具體的T,而func的參數(shù)是無界的,這里發(fā)生了一件參數(shù)類型捕獲的事情,在調(diào)用func的時(shí)候,類型被捕獲,而可以在actual方法中使用我們從func中傳遞進(jìn)來的無界參數(shù)。
可以使用無界通配符來接收多個(gè)類型的對(duì)象,然后根據(jù)不同的類型來交付給不同的方法來處理,可以回憶一下操作系統(tǒng)的中斷處理程序的處理方法,通過安裝一些中斷類型和與之對(duì)應(yīng)的handler,然后通過控制程序來將中斷處理信號(hào)分發(fā)到不同的handler中處理,其實(shí)思想是一樣的,可以看一下下面的代碼來理解這個(gè)模型:

    static  void actual(Holder holder) {
        T data = holder.getData();
        if (data instanceof String) {
            actual((String) data);
        } else if (data instanceof Integer) {
            actual((Integer) data);
        } else if (data instanceof Double) {
            actual((Double) data);
        }
    }

    static void actual(String holder) {
        System.out.print("string:" + holder);
    }

    static void actual(Integer holder) {
        System.out.println("Integer:" + holder);
    }

    static void actual(Double holder) {
        System.out.println("double:" + holder);
    }

    static void func(Holder holder) {
        actual(holder);
    }

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/70560.html

相關(guān)文章

  • Java泛型

    摘要:虛擬機(jī)中并沒有泛型類型對(duì)象,所有的對(duì)象都是普通類。其原因就是泛型的擦除。中數(shù)組是協(xié)變的,泛型是不可變的。在不指定泛型的情況下,泛型變量的類型為該方法中的幾種類型的同一個(gè)父類的最小級(jí),直到。 引入泛型的主要目標(biāo)有以下幾點(diǎn): 類型安全 泛型的主要目標(biāo)是提高 Java 程序的類型安全 編譯時(shí)期就可以檢查出因 Java 類型不正確導(dǎo)致的 ClassCastException 異常 符合越早出...

    woshicixide 評(píng)論0 收藏0
  • 對(duì)比Java泛型中的extends/super和Kotlin的out/in

    摘要:使用強(qiáng)轉(zhuǎn)的話,只能強(qiáng)轉(zhuǎn)成和它的基類,如果強(qiáng)轉(zhuǎn)成的子類的話,有可能會(huì)報(bào)運(yùn)行時(shí)異常。擁有類型,它是的子類型因此,我們可以將賦給類型為的變量在聲明處設(shè)置后,就可以和或它的子類進(jìn)行比較了。 歡迎關(guān)注我的博客:songjhhs blog原文連接:對(duì)比Java泛型中的extends/super和Kotlin的out/in 在 Java 泛型中,有一個(gè)叫做通配符上下界 bounded wildca...

    LittleLiByte 評(píng)論0 收藏0
  • 【從基礎(chǔ)學(xué) Java泛型

    摘要:泛型方法泛型類中可以定義靜態(tài)非靜態(tài)的泛型方法。上述泛型類會(huì)被替換成下面形式一般使用第一個(gè)限定類型替換變?yōu)樵碱愋停瑳]有限定類型,使用替換。 引言 在面向?qū)ο蟮氖澜缋?,我們?nèi)绻枰粋€(gè)容器來盛裝對(duì)象。舉個(gè)例子:一個(gè)籃子。我們可以用這個(gè)籃子裝蘋果,也可以用這個(gè)籃子裝香蕉。基于 OOP 的思想,我們不希望為蘋果和香蕉分別創(chuàng)建不同的籃子;同時(shí),我們希望放進(jìn)籃子里的是蘋果,拿出來的還是蘋果。于是...

    huhud 評(píng)論0 收藏0
  • 第5章:可復(fù)用性的軟件構(gòu)建方法 5.2面向復(fù)用的構(gòu)造

    摘要:代碼使用泛型類中不依賴于類型參數(shù)的方法。委托依賴于動(dòng)態(tài)綁定,因?yàn)樗蠼o定的方法調(diào)用可以在運(yùn)行時(shí)調(diào)用不同的代碼段。委托捕獲操作并將其發(fā)送給另一個(gè)對(duì)象。委托可以被看作是在對(duì)象層次上的復(fù)用機(jī)制,而繼承是類層次上的復(fù)用機(jī)制。 大綱 設(shè)計(jì)可復(fù)用的類 繼承和重寫 重載(Overloading) 參數(shù)多態(tài)和泛型編程 行為子類型與Liskov替換原則 組合與委托 設(shè)計(jì)可復(fù)用庫與框架 API和庫...

    DevTalking 評(píng)論0 收藏0
  • 聊聊Java泛型及實(shí)現(xiàn)

    摘要:靜態(tài)變量是被泛型類的所有實(shí)例所共享的。所以引用能完成泛型類型的檢查。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。事實(shí)上,泛型類擴(kuò)展都不合法。 前言 和C++以模板來實(shí)現(xiàn)靜多態(tài)不同,Java基于運(yùn)行時(shí)支持選擇了泛型,兩者的實(shí)現(xiàn)原理大相庭徑。C++可以支持基本類型作為模板參數(shù),Java卻只能接受類作為泛型參數(shù);Java可以在泛型類的方法中取得...

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

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

0條評(píng)論

閱讀需要支付1元查看
<