<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, 評論 - 5, 引用 - 0
    數(shù)據(jù)加載中……

    generic-泛型/類屬(三)

    管中窺虎

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

    ?

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

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

    ?

    這一篇是接著上兩篇繼續(xù)的。

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

    一些零碎

    ?

    關(guān)于類:

    ?

    ?

    List? < ?String? > ?l1? = ? new ?ArrayList? < ?String? > ?();?

    List?
    < ?Integer? > ?l2? = ? new ?ArrayList? < ?Integer? > ?();?

    System.out.println(l1.getClass()?
    == ?l2.getClass());?

    ?

    這樣的代碼打印出什么?腦子有沒有點混亂?事實是 true ,雖然類型參數(shù)不一樣,但它們在運行時終歸是同一個類。一個 class 可以有不同的 type 。由于靜態(tài)的變量和方法是被這個類的所有實例共享的,所以在靜態(tài)的方法,初始化塊,靜態(tài)變量的聲明或初始化中引用類型變量(前面的 T 這一類的東西)是非法的。

    ?

    關(guān)于轉(zhuǎn)換和 instanceOf

    ?

    正因為類的類型是被所有的實例共享的,所以去問一個實例是否為特定的類型是無意義的。

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

    if ?(cs? instanceof ?Collection? < ?String? > ?)? {??} ? // ?illegal?

    這樣的代碼是非法的。

    ?

    Collection? < ?String? > ?cstr? = ?(Collection? < ?String? > ?)?cs;? // ?unchecked?warning?

    ?

    同樣的,上面這行代碼將會有 unchecked warning 因為它試圖做的類型檢查,是根本不會在運行時被執(zhí)行的。同樣的,類型變量也是無效的:

    ?

    < ?T? > ?T?badCast(T?t,?Object?o)? {? return ?(T)?o;? // ?unchecked?warning?

    }
    ?

    ?

    總而言之,類型變量在運行時是不存在的,意味著它們不會對運行表現(xiàn)增加任何時間上或者空間上的累贅,這樣挺好,但同時也意味著,別指望用它們來做類型轉(zhuǎn)換。

    ?

    ?

    關(guān)于數(shù)組

    ?

    一個數(shù)組對象的元素類型是不能為類型變量或者帶類型參數(shù)的類型,除非是一個非受限通配符類型,你可以聲明一個元素類型為類型變量或者帶類型參數(shù)的類型的數(shù)組類型,但是不能聲明這樣的數(shù)組對象。好吧,你舌頭打結(jié)了吧?說實話,在翻譯這段話前,我不僅舌頭打結(jié),連神經(jīng)都快打結(jié)了,即使如此,我還是不能肯定我翻譯的是否正確。原文如下:

    The component type of an array object may not be a type variable or a parameterized

    type, unless it is an (unbounded) wildcard type.You can declare array types whose

    element type is a type variable or a parameterized type, but not array objects.

    通過閱讀下面的代碼,也許幫助你理解這團(tuán)亂麻,之所以有上面這樣的復(fù)雜規(guī)定,是為了避免這樣的情形:

    ?

    List? < ?String? > ?[]?lsa? = ? new ?List? < ?String? > ?[ 10 ];? // ?實際上不被允許,現(xiàn)在只是假設(shè)可以這樣寫?

    Object?o?
    = ?lsa;?

    Object[]?oa?
    = ?(Object[])?o;?

    List?
    < ?Integer? > ?li? = ? new ?ArrayList? < ?Integer? > ?();?

    li.add(
    new ?Integer( 3 ));?

    oa[
    1 ]? = ?li;? // ?有錯,但通過了運行時的檢查?

    String?s?
    = ?lsa[ 1 ].get( 0 );? // ?run-time?error?-?ClassCastException?

    ?

    如果運行了數(shù)組元素為帶類型變量的類型,就會出現(xiàn)這樣的情況,明明通過了編譯,沒有任何 unchecked warning ,但在運行時卻出錯。所以泛型必須設(shè)計為這個樣子,以保證:如果你的整個應(yīng)用程序在 jdk1.5 下通過了編譯而且沒有 unchecked warning ,那它就是類型安全的。

    然而,你還可以用通配符數(shù)組,接下來是以上代碼的兩個改版。

    ?

    第一個讓數(shù)組類和數(shù)組對象都用了通配符,在最后一句,如果要賦值給 String ,就必須用顯示的類型轉(zhuǎn)換,雖然出了錯,那么可以說這不是機(jī)制的錯誤了,而是程序員的錯。

    ?

    List? < ? ? ? > ?[]?lsa? = ? new ?List? < ? ? ? > ?[ 10 ];? // ?ok,?array?of?unbounded?wildcard?type?

    Object?o?
    = ?lsa;?

    Object[]?oa?
    = ?(Object[])?o;?

    List?
    < ?Integer? > ?li? = ? new ?ArrayList? < ?Integer? > ?();?

    li.add(
    new ?Integer( 3 ));?

    oa[
    1 ]? = ?li;? // ?correct?

    String?s?
    = ?(String)?lsa[ 1 ].get( 0 );? // ?run?time?error,?but?cast?is?explicit?

    ?

    ?

    ?

    在第二個版本里,我們定義了帶類型參數(shù)的類型的數(shù)組類,但數(shù)組對象用了通配符,這樣是合法的,但不安全,產(chǎn)生了 unchecked warning ,而且最終也確實出錯了。但至少,我們得到了警告。

    ?

    List? < ?String? > ?[]?lsa? = ? new ?List? < ? ? ? > ?[ 10 ];? // ?unchecked?warning?-?this?is?unsafe!?

    Object?o?
    = ?lsa;?

    Object[]?oa?
    = ?(Object[])?o;?

    List?
    < ?Integer? > ?li? = ? new ?ArrayList? < ?Integer? > ?();?

    li.add(
    new ?Integer( 3 ));?

    oa[
    1 ]? = ?li;? // ?correct?

    String?s?
    = ?lsa[ 1 ].get( 0 );? // ?run?time?error,?but?we?were?warned?

    ?

    ?

    ?

    同樣的,試圖創(chuàng)造一個元素類型是類型變量的數(shù)組對象是通過不了編譯的:

    ?

    這些錯誤的原因歸結(jié)起來也是我們之前討論過的了,就是因為運行時,這些類型變量是不存在的,無法決定數(shù)組的實際類型。

    要突破這些限制,可以使用 類名稱字面常量( class literal )作為運行時類型標(biāo)記,請看下文。

    ?

    ?

    以類名稱字面常量作為運行時類型標(biāo)記

    Jdk1.5 里, java.lang.Class 是泛型的,這就有趣了, Class 類有個類型參數(shù) T ,那 T 代表什么? T 代表了 Class 類的對象所代表的類型,又來繞口令了不是?

    舉例吧: String.class 的類型就是 Class<String> Serializable.class 的類型就是 Class < Serializable > 。現(xiàn)在 Class 類的 newInstance() 方法返回一個 T ,你現(xiàn)在在創(chuàng)造對象的時候獲得的類型更加精確了。( 1.4 里是固定地返回 Object

    假設(shè)你要寫一個工具方法,從數(shù)據(jù)庫里執(zhí)行一個 SQL 查詢,將符合查詢的結(jié)果以對象集合返回,有一鐘方法就是顯示的使用一個工廠對象,如下:

    interface ?Factory? < ?T? > ? {?T?make();?} ?

    public ? < ?T? > ?Collection? < ?T? > ?select(Factory? < ?T? > ?factory,?String?statement)? {?

    ???????Collection?
    < ?T? > ?result? = ? new ?ArrayList? < ?T? > ?();?

    /* ?run?sql?query?using?jdbc? */ ?

    ?????
    for ?( /* ?iterate?over?jdbc?results? */ ?)? {?

    ??????T?item?
    = ?factory.make();?

    /* ?use?reflection?and?set?all?of?item’s?fields?from?sql?results? */ ?

    ??????result.add(item);?

    ??????}
    ?

    ??????
    return ?result;?

    }
    ?

    你可以這樣調(diào)用它:

    ?

    select( new ?Factory? < ?EmpInfo? > ?()?{?

    public ?EmpInfo?make()?{?

    ???return ? new ?EmpInfo();?

    }?

    }?,?”selection?string”);?

    ?

    或者聲明一個實現(xiàn) Factory 接口的類 EmpInfoFactory

    class ?EmpInfoFactory? implements ?Factory? < ?EmpInfo? > ??{?

    public ?EmpInfo?make()?{?

    ??
    return ? new ?EmpInfo();?

    }?

    }?

    然后這樣調(diào)用它:

    select(getMyEmpInfoFactory(),?”selection?string”);?

    ?

    這兩個辦法的缺點就是,你要么在調(diào)用處寫上羅嗦的工廠類,要么為每個類都寫一個工廠類,在每個調(diào)用的地方傳入一個工廠對象,這看起來也不怎么自然。

    類名稱字面常量來作為一個工廠對象就很自然,它可以用于反射機(jī)制,如果不用泛型,可以這樣寫:

    C...ollection emps = sqlUtility.select(EmpInfo.class, ”select * from emps”);

    public ? static ?Collection?select(Class?c,?String?sqlStatement)?{?

    ???Collection?result?
    = ? new ?ArrayList();?

    ???
    /* ?run?sql?query?using?jdbc? */ ?

    ???
    for ?(? /* ?iterate?over?jdbc?results? */ ?)?{?

    ???????Object?item?
    = ?c.newInstance();?

    ??????
    /* ?use?reflection?and?set?all?of?item’s?fields?from?sql?results? */ ?

    ??????result.add(item);?

    ???}?
    return ?result;?

    }?

    ?

    然而這樣我們得不到我們想要的包含確切的類型的對象集,而現(xiàn)在 Class 是泛型的了,我們可以用它來達(dá)到目的:

    Collection? < ?EmpInfo? > ?emps? = ??sqlUtility.select(EmpInfo. class ,?”select? * ?from?emps”);?

    public ? static ? < ?T? > ?Collection? < ?T? > ?select(Class? < ?T? > ?c,?String?sqlStatement)?{?Collection? < ?T? > ?result? = ? new ?ArrayList? < ?T? > ();?

    ???
    /* ?run?sql?query?using?jdbc? */ ?

    ???
    for ?(? /* ?iterate?over?jdbc?results? */ ?)?{?T?item? = ?c.newInstance();?

    ??????
    /* ?use?reflection?and?set?all?of?item’s?fields?from?sql?results? */ ?

    ??????result.add(item);?

    ???}?
    return ?result;?

    }?

    精確的類型,類型安全。齊活兒了。

    ?

    這一篇到此為止,泛型的部分還剩下比較復(fù)雜的兩個部分,經(jīng)過考慮后決定延后完成,先完成 tiger 的其他幾個簡易的新特色會比較有趣些。

    posted on 2006-08-22 11:17 Binary 閱讀(336) 評論(0)  編輯  收藏 所屬分類: j2se

    主站蜘蛛池模板: 久久亚洲日韩精品一区二区三区| 亚洲毛片免费观看| 国产精品视频白浆免费视频| 亚洲国色天香视频| 亚洲国产成人VA在线观看| 精品国产麻豆免费人成网站| 精品国产成人亚洲午夜福利| 激情97综合亚洲色婷婷五| 亚色九九九全国免费视频| 人妖系列免费网站观看| 亚洲国产品综合人成综合网站| 亚洲国产精品无码久久青草| 222www在线观看免费| 一区二区三区在线免费观看视频| 亚洲午夜久久久精品电影院| 亚洲精品亚洲人成在线观看下载| 国产香蕉免费精品视频| 一本久久A久久免费精品不卡| 亚洲一级高清在线中文字幕| 狠狠综合久久综合88亚洲| 四虎成人免费网址在线| 无码av免费网站| 一级人做人a爰免费视频| 亚洲综合激情五月色一区| 亚洲成人免费在线| 亚洲人成网站在线观看播放动漫| 免费很黄很色裸乳在线观看| 精品亚洲成a人在线观看| 亚洲视频在线观看地址| 色噜噜亚洲精品中文字幕| 日本一道在线日本一道高清不卡免费 | 中文字幕免费观看视频| 在线a亚洲老鸭窝天堂av高清| 国产日韩成人亚洲丁香婷婷| 免费观看黄网站在线播放| 外国成人网在线观看免费视频| 亚州**色毛片免费观看| 亚洲成AV人片在WWW| 国产成+人+综合+亚洲专| 久久精品国产亚洲av水果派| 亚洲日韩欧洲乱码AV夜夜摸|