隨筆 - 19, 文章 - 1, 評論 - 21, 引用 - 0
          數(shù)據(jù)加載中……

          Java5新特性-泛型的使用總結(jié)(一)

          Java5的泛型的語法,已經(jīng)有很多帖子講了,這里依據(jù)我的一些個人理解做一次總結(jié),一方面是為了將我近一段時間對泛型的學(xué)習(xí)落實到紙面,畢竟有很多想法,如果只是存在于腦子里,過一段時間也就淡忘了,總要留下點(diǎn)文字便于以后回顧;另一方面,也希望拿出點(diǎn)東西來與大家交流分享,這樣才能不斷的得到提高。

          泛型是什么
          簡單的來說,泛型可以認(rèn)為是類型參數(shù)化的技術(shù)。相對于類型的參數(shù)化,在傳統(tǒng)的java代碼中,我們可以理解為所有的參數(shù)都是值的參數(shù)化,例如以下代碼:
           1 package org.dbstar.generic;
           2 
           3 public class ValueHolder {
           4     private String value;
           5 
           6     public ValueHolder(String value) {
           7         this.value = value;
           8     }
           9 
          10     public String getValue() {
          11         return value;
          12     }
          13 
          14     public void setValue(String value) {
          15         this.value = value;
          16     }
          17 }
          其中的成員變量、構(gòu)造函數(shù)參數(shù)和方法參數(shù),都可以認(rèn)為是值的參數(shù)化的體現(xiàn)。但是,不管值如何變化,值的類型只能局限于String及其子類,如果我們想讓ValueHolder同時也能持有一個Integer類型的值,那么在傳統(tǒng)的Java代碼中,只能將成員變量的類型定義為Object,如下:
           1 package org.dbstar.generic;
           2 
           3 public class ValueHolder {
           4     private Object value;
           5 
           6     public ValueHolder(Object value) {
           7         this.value = value;
           8     }
           9 
          10     public Object getValue() {
          11         return value;
          12     }
          13 
          14     public void setValue(Object value) {
          15         this.value = value;
          16     }
          17 }
          使用Object版的ValueHolder的代碼看起來會像這樣:
          1     public static void main(String[] args) {
          2         ValueHolder vhi = new ValueHolder(new Integer(1));
          3         ValueHolder vhs = new ValueHolder("abc");
          4         ValueHolder vho = new ValueHolder(new Object());
          5         System.out.println("ValueHolder of Integer=" + vhi.getValue());
          6         System.out.println("ValueHolder of String=" + vhs.getValue());
          7         System.out.println("ValueHolder of Object=" + vho.getValue());
          8     }
          輸出結(jié)果為:
          1 ValueHolder of Integer=1
          2 ValueHolder of String=abc
          3 ValueHolder of Object=java.lang.Object@757aef
          幸運(yùn)的是,Java5給我們提供了一個將value的類型也作為一個參數(shù)來設(shè)置的方法,那就是泛型,下面是將value的類型也參數(shù)化后的ValueHolder實現(xiàn):
           1 package org.dbstar.generic;
           2 
           3 public class ValueHolder<E> {
           4     private E value;
           5 
           6     public ValueHolder(E value) {
           7         this.value = value;
           8     }
           9 
          10     public E getValue() {
          11         return value;
          12     }
          13 
          14     public void setValue(E value) {
          15         this.value = value;
          16     }
          17 }
          其中,value就是值的參數(shù)化,value的類型現(xiàn)在定義為E,<E>就是類型的參數(shù)化。使用ValueHolder的代碼也相應(yīng)發(fā)生了變化:
          1         ValueHolder<Integer> vhi = new ValueHolder<Integer>(new Integer(1));
          2         ValueHolder<String> vhs = new ValueHolder<String>("abc");
          3         ValueHolder<Object> vho = new ValueHolder<Object>(new Object());
          4         System.out.println("ValueHolder of Integer=" + vhi.getValue().intValue());
          5         System.out.println("ValueHolder of String=" + vhs.getValue().substring(1));
          6         System.out.println("ValueHolder of Object=" + vho.getValue());
          根據(jù)ValueHolder類型定義的不同,類型參數(shù)<E>在不同場合代表了不同的實際類型。

          泛型的賦值
          與值參數(shù)的賦值不同的是,類型參數(shù)的賦值有其特殊性,下面來逐一說明:
          A。同類型賦值:
          1         ValueHolder<Integer> vhi = new ValueHolder<Integer>(new Integer(1));
          2         ValueHolder<Integer> vhi2 = vhi;
          3         vhi2.setValue(new Integer(2));
          4         System.out.println("ValueHolder of Integer2=" + vhi2.getValue().intValue());
          這種賦值后的變量,與源變量具有完全一致的操作,包括獲取泛型變量和在方法參數(shù)中設(shè)置泛型變量。
          B。超類型賦值:
          1         ValueHolder<Integer> vhi = new ValueHolder<Integer>(new Integer(1));
          2         ValueHolder<Number> vhi3 = vhi;//實際上,這是不允許的,會導(dǎo)致編譯錯誤
          3         ValueHolder<? extends Number> vhi2 = vhi;//必須要這樣寫
          4         System.out.println("ValueHolder of Integer2=" + vhi2.getValue().intValue());
          5         vhi2.setValue(new Integer(2));//超類型賦值后,操作受到限制,會導(dǎo)致編譯錯誤
          6         vhi2.setValue(null);//只有設(shè)置null值才是合法的,其他值一概不允許設(shè)置
          這種賦值后的變量,能調(diào)用返回值為泛型變量的方法,但是只能使用新泛型變量類型的方法,而不能再使用原有泛型變量類型上的方法,這樣說有點(diǎn)繞,舉例來說,上面的vhi2就只能使用Number類型上定義的方法,而無法再使用原先在Integer類型上定義的方法了。
          ValueHolder<?>等效于ValueHolder<? extends Object>,因為Object是所有類的超類。
          C。子類型賦值:
          1         @SuppressWarnings("unchecked")
          2         ValueHolder<Integer> vhi3 = (ValueHolder<Integer>) vhi2;
          和值參數(shù)的賦值一樣,超類型的泛型變量往子類型的泛型變量賦值,需要強(qiáng)制轉(zhuǎn)換,轉(zhuǎn)換后的vhi3與vhi具有完全一致的操作。但是,需要注意的一點(diǎn)是,這種轉(zhuǎn)換會導(dǎo)致一個unchecked的編譯時警告,而且,若無法完成轉(zhuǎn)換,會導(dǎo)致一個運(yùn)行時的ClassCastException異常,例如:
          1         @SuppressWarnings("unchecked")
          2         ValueHolder<Double> vhi3 = (ValueHolder<Double>) vhi2;//這里不會拋出異常
          3         vhi3.setValue(new Double(12.5));
          4         System.out.println("ValueHolder of Double=" + vhi3.getValue().doubleValue());
          5         System.out.println("ValueHolder of Integer=" + vhi.getValue().intValue());//會在這里拋出ClassCastException
          上例中,vhi2將Integer類型轉(zhuǎn)換成了超類型Number,而vhi3又將Number強(qiáng)類型轉(zhuǎn)換成了Double,這也是允許的,不會引發(fā)編譯時錯誤或者運(yùn)行時錯誤。下面甚至還可以給vhi3設(shè)置一個Double的值,值得注意的是,vhi3其實就是vhi,我們給一個Integer的變量設(shè)置了一個Double的值,卻沒有引發(fā)任何異常,還真是詭異的很。隨后,我們在調(diào)用vhi.getValue().intValue()時,才終于引發(fā)了ClassCastException。由此可見,這種強(qiáng)類型轉(zhuǎn)換有時候會使錯誤變得非常隱晦難于發(fā)現(xiàn),我們應(yīng)該盡量避免這種轉(zhuǎn)換的使用。
          D。傳統(tǒng)代碼賦值:
          1         @SuppressWarnings("unchecked")
          2         ValueHolder vh = vhi;
          3         vh.setValue(new Integer(3));
          不指定類型參數(shù)的泛型類,稱之為row type,這是Java5泛型為了與老版本的代碼兼容而選擇的一種處理方式。Row type的泛型類中,所有的類型參數(shù)都被當(dāng)做Object來處理,也就是說,ValueHolder可以當(dāng)做ValueHolder<Object>來處理,但是與ValueHolder<Object>又有所不同,因為ValueHolder<Integer>是不能被轉(zhuǎn)換為ValueHolder<Object>的,而能轉(zhuǎn)換的ValueHolder<? extends Object>又不能調(diào)用setValue方法(當(dāng)然可以設(shè)置null值,而其他非null值不能設(shè)置)。值得注意的是,轉(zhuǎn)換到傳統(tǒng)代碼,以及使用傳統(tǒng)代碼調(diào)用有泛型參數(shù)的方法,會引起一個unchecked的編譯時警告。

          posted on 2010-02-04 23:55 dbstar 閱讀(393) 評論(0)  編輯  收藏 所屬分類: Java


          只有注冊用戶登錄后才能發(fā)表評論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 贵州省| 垦利县| 彭山县| 大埔区| 牡丹江市| 台东县| 张家口市| 临桂县| 介休市| 南城县| 吉安市| 威海市| 绥宁县| 油尖旺区| 介休市| 桃园市| 黄平县| 思南县| 沂水县| 仪征市| 扶余县| 秦安县| 荔浦县| 万荣县| 常宁市| 大宁县| 封开县| 杭锦旗| 平昌县| 漠河县| 曲水县| 静乐县| 休宁县| 焦作市| 巴楚县| 舞阳县| 贺州市| 博白县| 凤翔县| 五台县| 图木舒克市|