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

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

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

    Vincent

    Vicent's blog
    隨筆 - 74, 文章 - 0, 評(píng)論 - 5, 引用 - 0
    數(shù)據(jù)加載中……

    generic-泛型/類屬

    管中窺虎

    在學(xué)習(xí) java 1.5 的過程中,我使用了 sun 公布的 tutorial ,這份文檔寫的比較詳盡易明,但是對(duì)于想快速了解 tiger 而且具有較好 java 基礎(chǔ)的人來說,大篇幅的英文文檔是比較耗時(shí)間和非必需的,所以我將會(huì)歸納這份文檔的主要內(nèi)容,在保證理解的底線上,盡力減少閱讀者需要的時(shí)間。

    ?

    在以下地址可以進(jìn)入各新增語(yǔ)言特色介紹以及下載相關(guān)文檔(若有)。

    http://java.sun.com/j2se/1.5.0/docs/relnotes/features.html

    ?

    第一道虎紋: generic -泛型 / 類屬

    什么是泛型

    泛型讓你在類這一層次上進(jìn)行抽象??纯蠢樱?br />

    List?myIntList? = ? new ?LinkedList();? // ?1?

    myIntList.add(
    new ?Integer( 0 ));? // ?2?

    Integer?x?
    = ?(Integer)?myIntList.iterator().next();? // ?3?

    ?

    ?

    3 句的轉(zhuǎn)換類型有點(diǎn)麻煩吧~?編譯器只能保證容器類里放的是 Object 對(duì)象,要使用他們只能這樣去轉(zhuǎn)換。而且這樣的轉(zhuǎn)換也并不是完全安全的,程序員可能犯錯(cuò)誤,容器里的對(duì)象未必是他以為的對(duì)象。有沒有辦法顯式地表達(dá)出程序員的意圖,將該容器限制為只能保存特定類型的對(duì)象?這正是 generic -泛型的核心用意。

    ?

    ?

    List? < ?Integer? > ?myIntList? = ? new ?LinkedList? < ?Integer? > ?();? // ?1’?

    myIntList.add(
    new ?Integer( 0 ));? // 2’?

    Integer?x?
    = ?myIntList.iterator().next();? // ?3’?

    ?

    ?

    這樣子我們就聲明了一個(gè)只放 Integer List ,我們說 List 是一個(gè) generic Interface ,接收了一個(gè)類型參數(shù),在上例中就是 Integer 。在初始化的時(shí)候,同樣的也指定了這個(gè)類型參數(shù)。

    要注意這些工作的效果不是僅僅把原來的第 3 句的轉(zhuǎn)換工作省掉,而是由此讓編譯器確保了這個(gè) List 在程序的任何位置任何時(shí)候都用以存放正確的類型,而原來的類型轉(zhuǎn)換僅僅告訴我們?cè)谶@一單點(diǎn)處程序員自己認(rèn)為的類型。

    泛型由此為程序,尤其是大型程序,帶來了可讀性和健壯性。

    定義簡(jiǎn)單的泛型

    ?

    ?public?interface?List?<?E?>?{?

    ???????void?add(E?x);?

    ??????Iterator?
    <?E?>?iterator();?

    }
    ?public?interface?Iterator?<?E?>?{?

    ?????????E?next();?

    ?????????boolean?hasNext();?

    }
    ?

    尖括號(hào)內(nèi)的標(biāo)識(shí)符就是一個(gè)類型形式參數(shù)。類似于方法的參數(shù),當(dāng)你使用的時(shí)候就替換一個(gè)實(shí)際參數(shù)進(jìn)去,只不過這個(gè)參數(shù)是個(gè)類型。在上面的例子中,我們就替換了一個(gè)

    Integer 類型進(jìn)去。

    在這里稍微說一下命名的規(guī)范,定義泛型中的形式參數(shù)時(shí),使用簡(jiǎn)潔有力又具有啟發(fā)性的名字,如果可以的話用單個(gè)字母更好。避免使用小寫,以免和普通的方法參數(shù)混淆。

    ?

    泛型與子類

    ?

    看看以下的例子語(yǔ)句合法嗎?

    ?

    List? < ?String? > ?ls? = ? new ?ArrayList? < ?String? > ?();? // 1?

    List?
    < ?Object? > ?lo? = ?ls;? // 2?

    ?

    2 句是行不通的,看看以下的語(yǔ)句:

    lo.add( new ?Object());? // ?3?

    String?s?
    = ?ls.get( 0 );? // ?4:?試圖將?Object?對(duì)象賦值給字符串對(duì)象,編譯錯(cuò)誤?

    簡(jiǎn)而言之就是,原有類型的繼承關(guān)系是不會(huì)反映到對(duì)應(yīng)的泛型上來,在上述情況下,任何兩個(gè)泛型類型都不存在繼承關(guān)系。那么,習(xí)慣了面向接口編程的我們?cè)鯓尤ミm應(yīng)這種嚴(yán)格的使用限制呢?

    ?

    通配符

    假如我們要用一個(gè)方法把一個(gè)容器內(nèi)的元素都 print 出來,可以用這樣的代碼來實(shí)現(xiàn) :

    void ?printCollection(Collection?c)? {?

    ?????????Iterator?i?
    = ?c.iterator();?

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

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

    ??????}

    ?????}
    ?

    如果我們用新的泛型和新的

    for 語(yǔ)句(你可以先不了解它,以后會(huì)談到)來嘗試同樣的功能,以下代碼可行嗎?

    ??void?printCollection(Collection?<?Object?>?c)?{?

    ??
    ????for?(Object?e?:?c)?{?

    ???????????System.out.println(e);?

    ?????????}

    }

    ?

    事實(shí)是,新的代碼的使用范圍非常有限,因?yàn)?/span> Collection < Object > 就只是一個(gè)放 Object 的容器泛類,它不是 任何其他 Collection 泛類的父類!真正擔(dān)任這個(gè)角色的是:

    Collection < ? >

    這個(gè)問號(hào)代表了未知, Collection < ? > 的元素可以是任何類型,這就是通配類型。

    現(xiàn)在我們可以這樣寫:

    void ?printCollection(Collection? < ? ? ? > ?c)? {?

    ??
    for ?(Object?e?:?c)? {?

    ?????????System.out.println(e);?

    ??????}
    ?
    }
    ?

    ?

    注意在循環(huán)里面,可以把元素賦值給一個(gè) Object 類型,因?yàn)闊o(wú)論 c 里放的是什么,它肯定是一個(gè) Object ,但向 c 里放置對(duì)象則是不安全的,因?yàn)椴恢?/span> c 的泛型是什么。如下面這樣是不行的:

    Collection? < ? ? ? > ?c? = ? new ?ArrayList? < ?String? > ?();?

    c.add(
    new ?Object());? // ?編譯錯(cuò)誤?

    ?

    add() 方面接納的是泛型的形式參數(shù)里描述的類型(或它的子類,希望你對(duì)此不感到混亂,呵呵。),然而此時(shí)我們只看到一個(gè)問號(hào),我們不知道它的類型參數(shù)是什么,當(dāng)然就不能放置對(duì)象進(jìn)去。唯一一個(gè)例外是 null ,它是任何一個(gè)類型的對(duì)象集的一分子。

    ?

    受限通配符

    省去一些說明性的代碼,以我們熟悉的幾何圖形家族例子來說明:

    ?

    public ? void ?drawAll(List? < ? ? ? extends ?Shape? > ?shapes)? {??} ?

    ?

    一個(gè) List<T> ,如果 T Shape 的子類,那么這個(gè) List 都可以被上面這個(gè)方法接納為參數(shù),這個(gè)就是受限的通配符。 Shape 就稱為這個(gè)通配符的上限。

    看看下面的代碼,怎樣?

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

    ??????shapes.add(
    0 ,? new ?Rectangle());? // ?compile-time?error!?

    }
    ?

    如上的方法依然是不行的,因?yàn)槲覀冎恢?/p> shapes Shape 或者其子類型的容器,然而具體類型是什么不知道,它未必是 Rectangle 的父類,所以不能放置元素進(jìn)去。

    ?

    總結(jié)起來,我們要了解的事情有:

    l???????? 泛型的用意

    l???????? 泛型的幾種形式(普通,通配符,受限通配符)

    l???????? 泛型與繼承關(guān)系一起使用時(shí)的易錯(cuò)傾向,尤其是向泛型容器添加元素的情況。

    posted on 2006-08-22 11:11 Binary 閱讀(545) 評(píng)論(1)  編輯  收藏 所屬分類: j2se

    評(píng)論

    # re: generic-泛型/類屬  回復(fù)  更多評(píng)論   

    學(xué)到不少。很想交朋友請(qǐng)教。
    2006-09-04 17:56 | liping
    主站蜘蛛池模板: 可以免费观看的毛片| 亚洲日韩看片无码电影| 久久久久久久亚洲精品| 亚洲乱码国产一区网址| 亚洲精品综合久久| 亚洲一区二区女搞男| 亚洲愉拍99热成人精品热久久| 国产av无码专区亚洲av果冻传媒| 国产精品亚洲综合专区片高清久久久 | 亚洲国产精品VA在线观看麻豆| 亚洲人成网亚洲欧洲无码久久| 亚洲男同帅GAY片在线观看| 亚洲国产无套无码av电影| 亚洲av最新在线网址| 亚洲精品免费视频| 亚洲一区二区三区精品视频 | 亚洲日韩国产一区二区三区| 久久久久国产成人精品亚洲午夜| 久久亚洲国产精品一区二区| 亚洲AV日韩AV永久无码绿巨人 | 亚洲色婷婷综合开心网| 亚洲春色在线视频| 亚洲精品美女久久久久9999| 亚洲国产精品免费观看| 99亚洲男女激情在线观看| 五月婷婷免费视频| 国产成人免费ā片在线观看老同学 | 老司机午夜性生免费福利| ssswww日本免费网站片| 国内精品久久久久影院免费| 8888四色奇米在线观看免费看| 国产一卡二卡3卡四卡免费| 国产精品免费播放| 九月丁香婷婷亚洲综合色| 亚洲高清资源在线观看| 亚洲AⅤ男人的天堂在线观看| 国产V片在线播放免费无码| 免费无码成人AV在线播放不卡| 黄瓜视频高清在线看免费下载| 免费大片在线观看网站| 亚洲av永久无码精品网站|