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

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

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

    posts - 3, comments - 15, trackbacks - 0, articles - 26
      BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理

    關(guān)于JAVA的泛類型簡介

    Posted on 2006-01-04 13:40 morcble的blog 閱讀(1823) 評論(0)  編輯  收藏 所屬分類: Java

    JAVA的泛類型,類似c++中的模板template,從JDK1.5開始支持編寫泛類型了。
    列如:
    ①jdk1.5以前的代碼
    import java.util.Hashtable;
    class Test {
      public static void main(String[] args) {
        Hashtable h = new Hashtable();
        h.put(new Integer(0), "value");
        String s = (String)h.get(new Integer(0));
        System.out.println(s);
      }
    }
    里面有強(qiáng)制的數(shù)據(jù)類型轉(zhuǎn)化。


    而在java(jdk1.5)的源代碼中則沒有了數(shù)據(jù)的強(qiáng)制轉(zhuǎn)化

    class Hashtable<Key, Value> {
      ...
      Value put(Key k, Value v) {...}
      Value get(Key k) {...}
    }
    import java.util.Hashtable;
    class Test {
      public static void main(String[] args) {
        Hashtable<Integer, String> h = new Hashtable<Integer, String>();
        h.put(new Integer(0), "value");
        String s = h.get(new Integer(0));    System.out.println(s);      }
    }


    ②泛型的多態(tài)

    class Utilities {
       <T extends Object> public static List<T> make(T first) {
         return new List<T>(first);
       }
    }

    強(qiáng)制 make 構(gòu)造新實(shí)例
    Utilities.make(Integer(0))
     

    ③ 受限泛型

    有時(shí)我們想限制可能出現(xiàn)的泛型類的類型實(shí)例化。在上面這個(gè)示例中,類 Hashtable 的類型參數(shù)可以用我們想用的任何類型參數(shù)進(jìn)行實(shí)例化,但是對于其它某些類,我們或許想將可能的類型參數(shù)集限定為給定類型 范圍內(nèi)的子類型。

    例如,我們可能想定義泛型 ScrollPane 類,它引用普通的帶有滾動條功能的 Pane 。被包含的 Pane 的運(yùn)行時(shí)類型通常會是類 Pane 的子類型,但是靜態(tài)類型就只是 Pane 。

    有時(shí)我們想用 getter 檢索被包含的 Pane ,但是希望 getter 的返回類型盡可能具體些。我們可能想將類型參數(shù) MyPane 添加到 ScrollPane 中,該類型參數(shù)可以用 Pane 的任何子類進(jìn)行實(shí)例化。然后可以用這種形式的子句: extends Bound 來說明 MyPane 的聲明,從而來設(shè)定 MyPane 的范圍:


    清單 7. 用 extends 子句來說明 MyPane 聲明
    class ScrollPane<MyPane extends Pane> { ... }
     


    其它泛型的例子
    class C<T> {
      static T member;

      C(T t) { member = t; }

      T getMember() { return member; }

      public static void main(String[] args) {
        C<String> c = new C<String>("test");
        System.out.println(c.getMember().toString());
        new C<Integer>(new Integer(1));
        System.out.println(c.getMember().toString());
      }
    }

     

    import java.util.Hashtable;
    interface Registry {
      public void register(Object o);
    }
    class C<T> implements Registry {
      int counter = 0;
      Hashtable<Integer, T> values;

      public C() {
        values = new Hashtable<Integer, T>();
      }

      public void register(Object o) {
        values.put(new Integer(counter), (T)o);
        counter++;
      }
    }

    輕松掌握 Java 泛型,第 3 部分
    克服 JSR-14 原型編譯器中泛型的限制
     

    級別: 初級

    Eric E. Allen, 博士研究生, Java 編程語言團(tuán)隊(duì),Rice 大學(xué)


    2003 年 6 月 09 日

    Java 開發(fā)人員和研究員 Eric Allen 繼續(xù)討論 JSR-14 和 Tiger 中的泛型類型,并著眼于在泛型類型中添加 naked 類型參數(shù)的 new 操作支持這一分支。
    這一系列主要討論在 Java 編程中添加泛型類型,本文是其中的一篇,將研究還未討論過的有關(guān)使用泛型的兩個(gè)限制之一,即添加對裸類型參數(shù)的 new 操作的支持(如類 C<T> 中的 new T() )。

    正如我 上個(gè)月所提到的那樣,Tiger 和 JSR-14 通過使用“類型消除(type erasure)”對 Java 語言實(shí)現(xiàn)泛型類型。使用類型消除(type erasure),泛型類型僅用于類型檢查;然后,用它們的上界替換它們。由此定義可知:消除將與如 new T() 之類的表達(dá)式?jīng)_突。

    如果假定 T 的界限是 Object ,那么這一表達(dá)式將被消除為 new Object() ,并且不管對 T 如何實(shí)例化( String 、 List 、 URLClassLoader 等等), new 操作將產(chǎn)生一個(gè)新的 Object 實(shí)例。顯然,這不是我們想要的。

    要添加對表達(dá)式(如 new T() )的支持,以及添加對我們上次討論過的其它與類型相關(guān)的操作(如數(shù)據(jù)類型轉(zhuǎn)換和 instanceof 表達(dá)式)的支持,我們必須采用某種實(shí)現(xiàn)策略而不是類型消除(如對于每個(gè)泛型實(shí)例化,使用獨(dú)立的類)。但對于 new 操作,需要處理其它問題。

    尤其是,為了實(shí)現(xiàn)對 Java 語言添加這種支持,必須對許多基本的語言設(shè)計(jì)問題作出決定。

    有效的構(gòu)造函數(shù)調(diào)用

    首先,為了對類型參數(shù)構(gòu)造合法的 new 表達(dá)式(如 new T() ),必須確保我們調(diào)用的構(gòu)造函數(shù)對于 T 的每個(gè)實(shí)例化都有效。但由于我們只知道 T 是其已聲明界限的子類型,所以我們不知道 T 的某一實(shí)例化將有什么構(gòu)造函數(shù)。要解決這一問題,可以用下述三種方法之一:

    要求類型參數(shù)的所有實(shí)例化都包括不帶參數(shù)的(zeroary)構(gòu)造函數(shù)。
    只要泛型類的運(yùn)行時(shí)實(shí)例化沒有包括所需的構(gòu)造函數(shù),就拋出異常。
    修改語言的語法以包括更詳盡的類型參數(shù)界限。
    第 1 種方法:需要不帶參數(shù)的構(gòu)造函數(shù)

    只要求類型參數(shù)的所有實(shí)例化都包括不帶參數(shù)的構(gòu)造函數(shù)。該解決方案的優(yōu)點(diǎn)是非常簡單。使用這種方法也有先例。

    處理類似問題的現(xiàn)有 Java 技術(shù)(象 JavaBean 技術(shù))就是通過要求一個(gè)不帶參數(shù)的構(gòu)造函數(shù)來解決問題的。然而,該方法的一個(gè)主要缺點(diǎn)是:對于許多類,沒有合理的不帶參數(shù)的構(gòu)造函數(shù)。

    例如,表示非空容器的任何類在構(gòu)造函數(shù)中必然使用表示其元素的參數(shù)。包括不帶參數(shù)的構(gòu)造函數(shù)將迫使我們先創(chuàng)建實(shí)例,然后再進(jìn)行本來可以在構(gòu)造函數(shù)調(diào)用中完成的初始化。但該實(shí)踐會導(dǎo)致問題的產(chǎn)生(您可能想要閱讀 2002 年 4 月發(fā)表的本專欄文章“The Run-on Initializer bug pattern”,以獲取詳細(xì)信息;請參閱 參考資料。)

    第 2 種方法:當(dāng)缺少所需構(gòu)造函數(shù)時(shí),拋出異常

    處理該問題的另一種方法是:只要泛型類的運(yùn)行時(shí)實(shí)例化沒有包括所需構(gòu)造函數(shù),就拋出異常。請注意:必須在運(yùn)行時(shí)拋出異常。因?yàn)?Java 語言的遞增式編譯模型,所以我們無法靜態(tài)地確定所有將在運(yùn)行時(shí)發(fā)生的泛型類的實(shí)例化。例如,假設(shè)我們有如下一組泛型類:


    清單 1.“裸”類型參數(shù)的 New 操作

    class C<T> {
      T makeT() {
        return new T();
      }
    }

    class D<S> {
      C<S> makeC() {
        return new C<S>();
      }
    }
     


    現(xiàn)在,在類 D<S> 中,構(gòu)造了類 C<S> 的實(shí)例。然后,在類 C 的主體中,將調(diào)用 S 的不帶參數(shù)的構(gòu)造函數(shù)。這種不帶參數(shù)的構(gòu)造函數(shù)存在嗎?答案當(dāng)然取決于 S 的實(shí)例化!

    比方說,如果 S 被實(shí)例化為 String ,那么答案是“存在”。如果它被實(shí)例化為 Integer ,那么答案是“不存在”。但是,當(dāng)編譯類 D 和 C 時(shí),我們不知道其它類會構(gòu)造什么樣的 D<S> 實(shí)例化。即使我們有可用于分析的整個(gè)程序(我們幾乎從來沒有這樣的 Java 程序),我們還是必須進(jìn)行代價(jià)相當(dāng)高的流分析來確定潛在的構(gòu)造函數(shù)問題可能會出現(xiàn)在哪里。

    此外,這一技術(shù)所產(chǎn)生的錯誤種類對于程序員來說很難診斷和修復(fù)。例如,假設(shè)程序員只熟悉類 D 的頭。他知道 D 的類型參數(shù)的界限是缺省界限( Object )。如果得到那樣的信息,他沒有理由相信滿足聲明類型界限(如 D<Integer> )的 D 的實(shí)例化將會導(dǎo)致錯誤。事實(shí)上,它在相當(dāng)長的時(shí)間里都不會引起錯誤,直到最后有人調(diào)用方法 makeC 以及(最終)對 C 的實(shí)例化調(diào)用方法 makeT 。然后,我們將得到一個(gè)報(bào)告的錯誤,但這將在實(shí)際問題發(fā)生很久以后 ― 類 D 的糟糕實(shí)例化。

    還有,對所報(bào)告錯誤的堆棧跟蹤甚至可能不包括任何對這個(gè)糟糕的 D 實(shí)例的方法調(diào)用!現(xiàn)在,讓我們假設(shè)程序員無權(quán)訪問類 C 的源代碼。他對問題是什么或如何修正代碼將毫無頭緒,除非他設(shè)法聯(lián)系類 C 的維護(hù)者并獲得線索。

    第 3 種方法:修改語法以獲得更詳盡的界限

    另一種可能性是修改語言語法以包括更詳盡的類型參數(shù)界限。這些界限可以指定一組可用的構(gòu)造函數(shù),它們必須出現(xiàn)在參數(shù)的每一個(gè)實(shí)例化中。因而,在泛型類定義內(nèi)部,唯一可調(diào)用的構(gòu)造函數(shù)是那些在界限中聲明的構(gòu)造函數(shù)。

    同樣,實(shí)例化泛型類的客戶機(jī)類必須使用滿足對構(gòu)造函數(shù)存在所聲明的約束的類來這樣做。參數(shù)聲明將充當(dāng)類與其客戶機(jī)之間的契約,這樣我們可以靜態(tài)地檢查這兩者是否遵守契約。

    與另外兩種方法相比,該方法有許多優(yōu)點(diǎn),它允許我們保持第二種方法的可表達(dá)性以及與第一種方法中相同的靜態(tài)檢查程度。但它也有需要克服的問題。

    首先,類型參數(shù)聲明很容易變得冗長。我們或許需要某種形式的語法上的甜頭,使這些擴(kuò)充的參數(shù)聲明還過得去。另外,如果在 Tiger 以后的版本中添加擴(kuò)充的參數(shù)聲明,那么我們必須確保這些擴(kuò)充的聲明將與現(xiàn)有的已編譯泛型類兼容。

    如果將對泛型類型的與類型相關(guān)的操作的支持添加到 Java 編程中,那么它采用何種形式還不清楚。但是,從哪種方法將使 Java 代碼盡可能地保持健壯(以及使在它遭到破壞時(shí)盡可能容易地修正)的觀點(diǎn)看,第三個(gè)選項(xiàng)無疑是最適合的。

    然而, new 表達(dá)式有另一個(gè)更嚴(yán)重的問題。


     

     回頁首
     

     

    多態(tài)遞歸

    更嚴(yán)重的問題是類定義中可能存在 多態(tài)遞歸。當(dāng)泛型類在其自己的主體中實(shí)例化其本身時(shí),發(fā)生多態(tài)遞歸。例如,考慮下面的錯誤示例:


    清單 2. 自引用的泛型類

    class C<T> {
      public Object nest(int n) {
        if (n == 0) return this;
        else return new C<C<T>>().nest(n - 1);
      }
    }
     


    假設(shè)客戶機(jī)類創(chuàng)建新的 C<Object> 實(shí)例,并調(diào)用(比方說) nest(1000) 。然后,在執(zhí)行方法 nest() 的過程中,將構(gòu)造新的實(shí)例化 C<C<Object>> ,并且對它調(diào)用 nest(999) 。然后,將構(gòu)造實(shí)例化 C<C<C<Object>>> ,以此類推,直到構(gòu)造 1000 個(gè)獨(dú)立的類 C 的實(shí)例化。當(dāng)然,我隨便選擇數(shù)字 1000;通常,我們無法知道在運(yùn)行時(shí)哪些整數(shù)將被傳遞到方法 nest 。事實(shí)上,可以將它們作為用戶輸入傳入。

    為什么這成為問題呢?因?yàn)槿绻覀兺ㄟ^為每個(gè)實(shí)例化構(gòu)造獨(dú)立類來支持泛型類型的與類型相關(guān)的操作,那么,在程序運(yùn)行以前,我們無法知道我們需要構(gòu)造哪些類。但是,如果類裝入器為它所裝入的每個(gè)類查找現(xiàn)有類文件,那么它會如何工作呢?

    同樣,這里有幾種可能的解決辦法:

    對程序可以產(chǎn)生的泛型類的實(shí)例化數(shù)目設(shè)置上限。
    靜態(tài)禁止多態(tài)遞歸。
    在程序運(yùn)行時(shí)隨需構(gòu)造新的實(shí)例化類。
    第 1 種:對實(shí)例化數(shù)設(shè)置上限

    我們對程序可以產(chǎn)生的泛型類的實(shí)例化數(shù)目設(shè)置上限。然后,在編譯期間,我們可以對一組合法的實(shí)例化確定有限界限,并且僅為該界限中的所有實(shí)例化生成類文件。

    該方法類似于在 C++ 標(biāo)準(zhǔn)模板庫中完成的事情(這使我們有理由擔(dān)心它不是一個(gè)好方法)。該方法的問題是,和為錯誤的構(gòu)造函數(shù)調(diào)用報(bào)告錯誤一樣,程序員將無法預(yù)知其程序的某一次運(yùn)行將崩潰。例如,假設(shè)實(shí)例化數(shù)的界限為 42,并且使用用戶提供的參數(shù)調(diào)用先前提到的 nest() 方法。那么,只要用戶輸入小于 42 的數(shù),一切都正常。當(dāng)用戶輸入 43 時(shí),這一計(jì)劃不周的設(shè)計(jì)就會失敗。現(xiàn)在,設(shè)想一下可憐的代碼維護(hù)者,他所面對的任務(wù)是重新組合代碼并試圖弄清楚幻數(shù) 42 有什么特殊之處。

    第 2 種:靜態(tài)禁止多態(tài)遞歸

    為什么我們不向編譯器發(fā)出類似“靜態(tài)禁止多態(tài)遞歸”這樣的命令呢?(唉!要是那么簡單就好了。)當(dāng)然,包括我在內(nèi)的許多程序員都會反對這種策略,它抑制了許多重要設(shè)計(jì)模式的使用。

    例如,在泛型類 List<T> 中,您真的想要防止 List<List<T>> 的構(gòu)造嗎?從方法返回這種列表對于構(gòu)建許多很常用的數(shù)據(jù)結(jié)構(gòu)很有用。事實(shí)證明我們無法防止多態(tài)遞歸,即使我們想要那樣,也是如此。就象靜態(tài)檢測糟糕的泛型構(gòu)造函數(shù)調(diào)用一樣,禁止多態(tài)遞歸會與遞增式類編譯發(fā)生沖突。我們先前的簡單示例(其中,多態(tài)遞歸作為一個(gè)簡單直接的自引用發(fā)生)會使這一事實(shí)變得模糊。但是,自引用對于在不同時(shí)間編譯的大多數(shù)類常常采用任意的間接級別。再提一次,那是因?yàn)橐粋€(gè)泛型類可以用其自己的類型參數(shù)來實(shí)例化另一個(gè)泛型類。

    下面的示例涉及兩個(gè)類之間的多態(tài)遞歸:


    清單 3. 相互遞歸的多態(tài)遞歸

    class C<T> {
      public Object potentialNest(int n) {
        if (n == 0) return this;
        else return new D<T>().nest(n - 1);
      }
    }

    class D<S> {
      public Object nest(int n) {
        return new C<C<S>>().nest(n);
      }
    }
     


    在類 C 或 D 中顯然沒有多態(tài)遞歸,但象 new D<C<Object>>().nest(1000) 之類的表達(dá)式將引起類 C 的 1000 次實(shí)例化。

    或許,我們可以將新屬性添加到類文件中,以表明類中所有不同泛型類型實(shí)例化,然后在編譯其它類時(shí)分析這些實(shí)例化,以進(jìn)行遞歸。但是,我們還是必須向程序員提供奇怪的和不直觀的錯誤消息。

    在上面的代碼中,我們在哪里報(bào)告錯誤呢?在類 D 的編譯過程中還是在包含不相干表達(dá)式 new D<C<Object>>().nest(1000) 的客戶機(jī)類的編譯過程中呢?無論是哪一種,除非程序員有權(quán)訪問類 C 的源代碼,否則他無法預(yù)知何時(shí)會發(fā)生編譯錯誤。

    第 3 種:實(shí)時(shí)構(gòu)造新的實(shí)例化類

    另一種方法是在程序運(yùn)行時(shí)按需構(gòu)造新的實(shí)例化類。起先,這種方法似乎與 Java 運(yùn)行時(shí)完全不兼容。但實(shí)際上,實(shí)現(xiàn)該策略所需的全部就是使用一個(gè)修改的類裝入器,它根據(jù)“模板(template)”類文件構(gòu)造新的實(shí)例化類。

    JVM 規(guī)范已經(jīng)允許程序員使用修改的類裝入器;事實(shí)上,許多流行的 Java 應(yīng)用程序(如 Ant、JUnit 和 DrJava)都使用它們。該方法的缺點(diǎn)是:修改的類裝入器必須與其應(yīng)用程序一起分布,以在較舊的 JVM 上運(yùn)行。因?yàn)轭愌b入器往往比較小,所以這個(gè)開銷不會大。
     

    主站蜘蛛池模板: 国产精品福利片免费看| 在线视频亚洲一区| 亚洲视频免费在线观看| 国产亚洲精品激情都市| 一个人看的hd免费视频| 在线亚洲精品福利网址导航| ssswww日本免费网站片| 亚洲自偷自偷偷色无码中文| 国产区在线免费观看| 精品国产亚洲一区二区三区| 一个人免费视频在线观看www| 亚洲精品国产精品乱码不卡√| 日本道免费精品一区二区| 亚洲精品制服丝袜四区| 国产精品免费AV片在线观看| 亚洲欧洲免费视频| 免费观看美女用震蛋喷水的视频| 亚洲国产成人无码av在线播放| 桃子视频在线观看高清免费完整 | 在线观看亚洲精品福利片| 久久免费国产精品| 亚洲精品自产拍在线观看动漫| 日本亚洲免费无线码| 国产精品亚洲精品久久精品 | 99xxoo视频在线永久免费观看| 久久99亚洲网美利坚合众国| 亚洲美女视频免费| 亚洲欧美成人av在线观看| 亚洲欧洲中文日韩久久AV乱码 | 亚洲人xxx日本人18| 国产精品免费_区二区三区观看| 国产99久久久久久免费看| 亚洲第一视频网站| 成人性生交大片免费看无遮挡| 香蕉视频在线观看免费| 亚洲日本中文字幕| 国产午夜影视大全免费观看| a毛片在线还看免费网站| 亚洲狠狠成人综合网| 亚洲黄片毛片在线观看| 亚洲无砖砖区免费|