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

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

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

    幻境
    We are extremely fortunate not to know precisely the kind of world we live in
    posts - 22,comments - 39,trackbacks - 0

    簡介

    泛型其實并不是一種新的語言元素,C++中早就就有,但是在C++之后的java卻沒有吸收這個特性,現(xiàn)在Java也有了泛型的特性,大概也和.Net的競爭有關(guān)系吧。

    首先看泛型的一個應(yīng)用。

    在過去,我們可能經(jīng)常要寫一些類似這樣的代碼:

    List stringList=new LinkedList();

    stringList.add("firstString");

    stringList.add("secondString");

    String str=(String)stringList.iterator().next();

     

    實際上第三行對String的類型轉(zhuǎn)換意義并不大,因為通常我們?nèi)绻诓僮饕粋€List,都是知道這個List里面放的是什么類型對象的,但是我們?nèi)绻贿@樣寫又通不過語法檢查。

    利用java的泛型機制,我們可以這么寫:

    List<String> stringList=new LinkedList<String>();

    stringList.add("firstString");

    stringList.add("secondString");

    String str=stringList.iterator().next();

     

    這樣做的好處是在定義容器的時候就指明了容器中的類型,一方面我們不再需要取一個元素時候做強制類型轉(zhuǎn)換,另外一方面如果在這個容器中放入的對象類型不符合要求,那么會在編譯時候產(chǎn)生一個錯誤,而不是在運行時候才拋出一個異常。

    另外這樣也提高了程序的可讀性。

    泛型類型的定義

    下面是一個簡單的使用泛型類的定義:

    public class MyGenericClass<T> {

        private T value;

     

        public T getValue() {

           return value;

        }

       

        public void setValue(T value) {

           this.value = value;

        }  

    }

     

    值得注意的一點是,靜態(tài)變量不能夠使用泛型定義,也就是說類似下面的語句是非法的:

     

    public class MyGenericClass<T> {

        public static T value;//錯誤的定義

    }

     

     

    此外,泛型的定義不會被繼承,舉個例子來說,如果AB的子類,而C是一個聲明了泛型定義的類型的話,C<A>不是C<B>的子類。為了更好的說明,可以看下面的代碼,這段代碼是錯誤的。

    List<String> strList =new ArrayList<String>();

    List<Object> objList=strList;  //錯誤的賦值

     

    不過這樣一段代碼是正確的:

    List<Object> strList =new ArrayList<Object>();

    strList.add("a string");

     

    統(tǒng)配類型

    假設(shè)我們需要這樣一個函數(shù),使用它可以把一個集合中所有的元素打印出來,在以前我們可能這樣定義:

    void printCollection(Collection c) {

        Iterator i = c.iterator();

        for (k = 0; k < c.size(); k++)

        {

           System.out.println(i.next());

        }

    }

     

    使用新的泛型特性我們可以這樣寫:

    void printCollection(Collection<Object> c)

    {

        for (Object e : c)

        {

           System.out.println(e);

        }

    }

     

    但是這樣有一個問題,假如我們現(xiàn)在有個對象類型是Collection<String>,那么我們不能夠?qū)⑺鳛閰?shù)傳給printCollection,因為Collection<String>并不是Collection<Object>的子類。

    為了解決這個問題,我們可以使用統(tǒng)配類型?,也就是定義成下面這個樣子:

    void printCollection(Collection<?> c)

    {

        for (Object e : c)

        {

           System.out.println(e);

        }

    }

     

    可以說Collection<?>是所有Collection的父類。

    再來看一段下面的代碼

    private void clearAllMaps(Collection<Map> c)

    {

           for(Map m:c)

           {

               m.clear();

           }

    }

     

    毫無疑問,它也存在上面我們所說的問題,也就是對HashMap之類Map的子類無法進行操作,但是如果我們將參數(shù)改成Collection<?>又不大合理,因為我們只希望對父類為Map的子類進行操作,那么我們可以這樣改寫:

    private void clearAllMaps(Collection<? extends Map> c)

    {

        for(Map m:c)

        {

           m.clear();

        }

    }

     

    類似于? extends Map之類的統(tǒng)配符稱為限定統(tǒng)配類型。

    假設(shè)一個對象h類型為Collection<HashMap>,那么我們將h作為參數(shù)傳給clearAllMaps,如下面一段代碼所示:

    List<HashMap<String,String>> h=new ArrayList<HashMap<String,String>>();

    HashMap<String,String> m=new HashMap<String,String>();

    m.put("key","value");

    h.add(m);

    clearAllMaps(h);

     

    對于在類似于上面所說,使用了? extend XXX的方法,值得注意的一點是不能夠在方法體內(nèi)用XXX的子類對象作為代替。如下面一段代碼是錯誤的:

    public void addRectangle(List<? extends Shape> shapes)

    {

        shapes.add(0, new Rectangle()); // 錯誤用法!

    }

     

    這里我們假設(shè)RectangleShape的一個子類。

    不允許這樣寫的原因比較簡單,因為調(diào)用該方法時候參數(shù)類型可能是Shape的另外一個子類。假如說Shape除了Rectangle這個子類以外還有另外一個子類Circle,那么我們可以把一個List<Circle>類型的對象作為參數(shù)傳給這個方法(注意這樣是合法的),而在方法體內(nèi)卻把一個Rectangle對象放到了shapes里面,這顯然是不合理的。

    除了extends,在泛型參數(shù)類型中還可以使用super關(guān)鍵字,參照下面一段程序:

    private void addString(Collection <? super String> c)

    {

           c.add("a String");

    }

     

    泛型函數(shù)

    我們在前面提到了統(tǒng)配類型,現(xiàn)在讓我們來設(shè)想一個函數(shù),它實現(xiàn)這樣的功能,將一個數(shù)組中的元素添加到一個Collection中,為了保證程序的通用性,我們可能會寫出另外一段錯誤的代碼:

    private void fromArrayToCollection(Object[] a, Collection<?> c)

    {

        for (Object o : a)

        {

           c.add(o); // 錯誤的代碼

        }

    }

     

    那么這個函數(shù)應(yīng)該怎么寫呢?我們可以通過對函數(shù)添加泛型參數(shù)的方法實現(xiàn),如下面所示:

    private <T> void  exfromArrayToCollection(T[] a,  Collection<T> c)

    {

           for (T o : a)

           {

               c.add(o); //這樣是正確的

           }

    }

     

    那么,在什么時候我們應(yīng)該使用統(tǒng)配類型,什么時候我們應(yīng)該使用泛型函數(shù)呢?答案是取決于函數(shù)參數(shù)之間,函數(shù)參數(shù)和返回值之間的類型依賴性。

    如果一個函數(shù)的參數(shù)類型與函數(shù)返回的參數(shù)沒有必然關(guān)聯(lián),同時對于該函數(shù)其他的參數(shù)的類型也沒有依賴關(guān)系,那么我們就應(yīng)該使用統(tǒng)配符,否則就應(yīng)該使用泛型函數(shù)。

    為了更清楚地說明這一點,我們可以看一下java.util包中Collections類型幾個方法的定義:

    class Collections {

        static void swap(List<?> list, int i, int j) {...}

        static <T> void  copy                                 (List<? super T> dest, List<? extends T> src)    {...}

    }

     

    其中swap函數(shù)實際上也可以這樣定義:

    static <T>void swap(List<T> list, int i, int j) {...}

     

    但是注意到這里泛型類型參數(shù)T只在參數(shù)中用到了一次,也就是說它和函數(shù)其他部分沒有依賴性,這可以看作是我們應(yīng)該使用?的一個標(biāo)志。

    copy方法中,拷貝源src中的元素必須是dest所能夠接受的,src中的元素必須是T的一個子類,但是具體它是哪種子類我們又不必關(guān)心,所以方法中使用了泛型作為一個類型參數(shù),同時也用了統(tǒng)配類型作為第二類型參數(shù)

    posted on 2005-05-12 10:55 閱讀(985) 評論(0)  編輯  收藏 所屬分類: 編程相關(guān)
    主站蜘蛛池模板: 免费乱理伦在线播放| 四虎在线免费视频| 全部免费毛片在线| 亚洲av永久无码| 女人张腿给男人桶视频免费版| 亚洲人成网址在线观看| 无码免费一区二区三区免费播放| 国产亚洲大尺度无码无码专线| 日本激情猛烈在线看免费观看| 国产在线19禁免费观看| 美女隐私免费视频看| 免费A级毛片无码A∨男男 | 国内外成人免费视频| 香蕉大伊亚洲人在线观看| 免费看国产成年无码AV片| 亚洲精品成a人在线观看夫| 日韩精品免费电影| 日韩免费高清一级毛片| 久久久青草青青国产亚洲免观| 一级有奶水毛片免费看| 亚洲av永久无码精品表情包| 4444www免费看| 亚洲AV成人影视在线观看| 四虎影永久在线高清免费| 国产成人无码精品久久久久免费 | 一个人看的免费视频www在线高清动漫 | 亚洲精品狼友在线播放| 秋霞人成在线观看免费视频 | 国产又大又粗又硬又长免费| 一区二区三区在线免费观看视频| 国产亚洲精AA在线观看SEE| 在线免费观看你懂的| 国产成人精品亚洲2020| 国产精品久久久久影院免费| 成人午夜免费视频| 1区1区3区4区产品亚洲| 免费看少妇作爱视频| 精品一区二区三区免费视频| 亚洲精品免费在线视频| 人人狠狠综合久久亚洲高清| a级毛片毛片免费观看久潮|