<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    廉頗老矣,尚能飯否

    java:從技術(shù)到管理

    常用鏈接

    統(tǒng)計

    最新評論

    java范型學習

    泛型不用考慮對象的具體類型。優(yōu)點在于,因為不用考慮對象的具體類型所以可以對一類對象執(zhí)行一定的相同操作;缺點在于,因為沒有考慮對象的具體類型所以就不能使用對象自帶的接口函數(shù)。泛型的最佳用同是實現(xiàn)容器類。在java中,范型是在編譯器中實現(xiàn)的,而不是在虛擬機中實現(xiàn)的,虛擬機對范型一無所知。因此,編譯器一定要把范型類修改為普通類,才能夠在虛擬機中執(zhí)行。在java中,這種技術(shù)稱之為“擦除”,也就是用Object類型替換范型(Comparable來替換所有范型)。當需要用到其他約束中定義的方法的時候,通過插入強制轉(zhuǎn)化代碼來實現(xiàn)。Wildcard支持另外一個關(guān)鍵字super,而范型方法不支持super關(guān)鍵字。下面是一個簡單的泛型類的代碼

    package demo;

    public class Name<T> {

     public Name() {
      this.firstName = null;
      this.secondName = null;
     }

     public Name(T firstName, T secondName) {
      this.firstName = firstName;
      this.secondName = secondName;
     }

     public T getFirstName() {
      return firstName;
     }

     public void setFirstName(T firstName) {
      this.firstName = firstName;
     }

     public T getSecondName() {
      return secondName;
     }

     public void setSecondName(T secondName) {
      this.secondName = secondName;
     }

     private T firstName;
     
     private T secondName;

    }

    ==================================================================

    package demo;

    public class Name {
     public Name() {
      this.firstName = null;
      this.secondName = null;
     }

     public Name(Object firstName, Object secondName) {
      this.firstName = firstName;
      this.secondName = secondName;
     }

     public Object getFirstName() {
      return firstName;
     }

     public void setFirstName(Object firstName) {
      this.firstName = firstName;
     }

     public Object getSecondName() {
      return secondName;
     }

     public void setSecondName(Object secondName) {
      this.secondName = secondName;
     }

     private Object firstName;
     
     private Object secondName;

    }


    每當你用一個具體類去實例化該范型時,編譯器都會在原生類的基礎(chǔ)上,通過強制約束和在需要的地方添加強制轉(zhuǎn)換代碼來滿足需求,但是不會生成更多的具體的類。
    Pair<Employee>  buddies  =  new  Pair<Employee>();

    在上述原生代碼中,此處參數(shù)類型是Object,理論上可以接納各種類型,但編譯器通過強制約束在此使用Employee(及子類)類型的參數(shù),其他類型編譯器一律報錯buddies.setFirst(new Employee("張三")); 在上述原生代碼中,getFirst()的返回值是一個Object類型,是不可以直接賦給類型為Employee的buddy的,但編譯器在此做了手腳,添加了強制轉(zhuǎn)化代碼,實際代碼應該是Employee buddy = (Employee)buddies.getFirst();這樣就合法了。但編譯器做過手腳的代碼你是看不到的,他是以字節(jié)碼的形式完成的。Employee buddy = buddies.getFirst();一般情況下不要涉及類型的具體信息。范型類可以繼承自某一個父類,或者實現(xiàn)某個接口,或者同時繼承父類并且實現(xiàn)接口。這樣的話,就可以對類型調(diào)用父類或接口中定義的方法了。
    public class Pair<T extends Comparable>
    ...{
       public boolean setSecond(T newValue) ...{
       boolean flag = false;
       If(newValue.compareTo(first)>0) ...{
         second = newValue;
         flag = true;
       }
       return flag;
    }
     
       private T first;
       private T second;
    }

    上面的范型T被添加了一個約束條件,那就是他必須實現(xiàn)Comparable接口,這樣的話,就可以對范型T使用接口中定義的方法了,也就可以實現(xiàn)2個元素大小的比較。為了簡化范型的設(shè)計,無論是繼承類還是實現(xiàn)接口,一律使用extends關(guān)鍵字。若同時添加多個約束,各個約束之間用“&”分隔,比如:public class Pair<T extends Comparable & Serializable>。那么編譯器是如何處理這種情況呢?前面講過,范型類最終都會被轉(zhuǎn)化為原生類。在前面沒有添加約束的時候,編譯器將范型通通替換為Object;而增加了約束之后,通通用第一個約束來替換范型
    ArrayList<Integer> l = new ArrayList<Integer>();
        test(l);  //此處編譯器會報錯!!
    Integer確實是Number的子類,但是,ArrayList<Integer>并不是ArrayList<Number>的子類,二者之間沒有任何的繼承關(guān)系
     public static void test(ArrayList<Number> l) ...{
            l.add(new Float(2));
        }

     在函數(shù)內(nèi)部,我們把Float類型的元素插入到鏈表中。因為鏈表是Number類型,這條語句沒問題。但是,如果實參是一個Integer類型的鏈表,他能存儲Float類型的數(shù)據(jù)嗎??顯然不能,這樣就會造成運行時錯誤。于是,編譯器干脆就不允許進行這樣的傳遞。在向容器類添加內(nèi)容的時候可能造成類型不匹配。
    ===================================================================

    //     1.在定義方法的時候使用Wildcard(也就是下述代碼中的問號)。
        public static void test1(ArrayList<? extends Number> l) ...{
            Integer n = new Integer(45);
            Number x = l.get(0); //從鏈表中取數(shù)據(jù)是允許的
            l.add(n);  //錯誤!!往鏈表里面插入數(shù)據(jù)是被編譯器嚴格禁止的!!
        }

    //     2.定義一個范型方法。代碼如下:
        public static <T extends Number> void test2(ArrayList<T> l) ...{
            Number n = l.get(0);
            T d = l.get(0);
            l.add(d);  //與上面的方法相比,插入一個范型數(shù)據(jù)是被允許的,相對靈活一些
            l.add(n);  //錯誤!!只可以插入范型數(shù)據(jù),絕不可插入具體類型數(shù)據(jù)。
        }

    只要我們對形參添加了一定的約束條件,那么我們在傳遞實參的時候,對實參的嚴格約束就會降低一些。上述代碼都指定了一個類Number,并用了extends關(guān)鍵字,因此,在傳遞實參的時候,凡是從Number繼承的類組成的鏈表,均可以傳遞進去。但上面代碼的注釋中也說的很清楚,為了不出現(xiàn)運行時錯誤,編譯器會對你調(diào)用的方法做嚴格的限制:凡是參數(shù)為范型的方法,一律不需調(diào)用!!

     

        public static void test5(ArrayList<? super Integer> l) ...{
            Integer n = new Integer(45);
            l.add(n);  //與上面使用extends關(guān)鍵字相反,往鏈表里面插入指定類型的數(shù)據(jù)是被允許的。
            Object x = l.get(0); //從鏈表里取出一個數(shù)據(jù)仍然是被允許的,不過要賦值給Object對象。
            l.add(x);   //錯誤!!將剛剛?cè)〕龅臄?shù)據(jù)再次插入鏈表是不被允許的。
        }

    對實參的限制更改為:必須是指定類型的父類。這里我們指定了Integer類,那么實參鏈表的元素類型,必須是Number類及其父類。下面我們重點討論一下上述代碼的第四條語句,為什么將剛剛?cè)〕龅臄?shù)據(jù)再次插入鏈表不被允許??道理很簡單,剛剛?cè)〕龅臄?shù)據(jù)被保存在一個Object類型的引用中,而鏈表的add方法只能接受指定類型Integer及其子類,類型不匹配當然不行。 

        //幫助函數(shù)
        public static <T>void helperTest5(ArrayList<T> l, int index) ...{
            T temp = l.get(index);
            l.add(temp);
        }
       
        //主功能函數(shù)
        public static void test5(ArrayList<? super Integer> l) ...{
            Integer n = new Integer(45);
            l.add(n); 
            helperTest5(l, 0);   //通過幫助類,將指定的元素取出后再插回去。
        }
    上述兩個函數(shù)結(jié)合的原理就是:利用Wildcard的super關(guān)鍵字來限制參數(shù)的類型(范型函數(shù)不支持super,要是支持的話就不用這么麻煩了),然后通過范型函數(shù)來完成取出數(shù)據(jù)的再存儲。注意:

    //1、不可以用一個本地類型(如int   float)來替換范型
    //2、運行時類型檢查,不同類型的范型類是等價的(Pair<String>與Pair<Employee>是屬于同一個類型Pair),
    //     這一點要特別注意,即如果a instanceof Pair<String>==true的話,并不代表a.getFirst()的返回值是一個String類型
    //3、范型類不可以繼承Exception類,即范型類不可以作為異常被拋出
    //4、不可以定義范型數(shù)組
    //5、不可以用范型構(gòu)造對象,即first = new T(); 是錯誤的
    //6、在static方法中不可以使用范型,范型變量也不可以用static關(guān)鍵字來修飾
    //7、不要在范型類中定義equals(T x)這類方法,因為Object類中也有equals方法,當范型類被擦除后,這兩個方法會沖突
    //8、根據(jù)同一個范型類衍生出來的多個類之間沒有任何關(guān)系,不可以互相賦值
    //     即Pair<Number> p1;  Pair<Integer> p2;   p1=p2;  這種賦值是錯誤的。
    //9、若某個范型類還有同名的非范型類,不要混合使用,堅持使用范型類
    //     Pair<Manager> managerBuddies = new Pair<Manager>(ceo, cfo);
    //     Pair rawBuddies = managerBuddies;  這里編譯器不會報錯,但存在著嚴重的運行時錯誤隱患



    柳德才
    13691193654
    18942949207
    QQ:422157370
    liudecai_zan@126.com
    湖北-武漢-江夏-廟山

    posted on 2009-04-16 23:31 liudecai_zan@126.com 閱讀(1104) 評論(0)  編輯  收藏 所屬分類: 程序人生

    主站蜘蛛池模板: 国产黄色免费观看| 日本亚洲高清乱码中文在线观看| 一级毛片a免费播放王色电影 | 国产免费午夜a无码v视频| 亚洲黄页网在线观看| 中文字幕人成无码免费视频| 亚洲自国产拍揄拍| 最新中文字幕免费视频| 亚洲91精品麻豆国产系列在线| 动漫黄网站免费永久在线观看| 久久久久精品国产亚洲AV无码| 国产免费不卡v片在线观看| 亚洲五月综合网色九月色| 成人毛片18女人毛片免费视频未| 自拍日韩亚洲一区在线| 午夜a级成人免费毛片| 激情婷婷成人亚洲综合| 亚洲精品国产精品乱码不卞| 精选影视免费在线 | 久久久亚洲欧洲日产国码农村| 91高清免费国产自产拍2021| 国产精品亚洲四区在线观看| 在线免费视频一区| kk4kk免费视频毛片| 亚洲国产精品久久久久久| a拍拍男女免费看全片| 亚洲精品无码mⅴ在线观看| 亚洲AV无码专区日韩| 久久青草国产免费观看| 亚洲中文久久精品无码1 | 免费精品人在线二线三线区别 | 亚洲六月丁香婷婷综合| 精品少妇人妻AV免费久久洗澡| 四虎精品成人免费视频| 亚洲国产成人一区二区精品区 | 日韩亚洲产在线观看| 久久久久亚洲?V成人无码| 99久久精品免费视频| 亚洲日本va一区二区三区| 亚洲综合无码AV一区二区| 香蕉97超级碰碰碰免费公|