管中窺虎
在學(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)于類:
?






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








這樣的代碼是非法的。
?

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






?
總而言之,類型變量在運行時是不存在的,意味著它們不會對運行表現(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ī)定,是為了避免這樣的情形:
?














?
如果運行了數(shù)組元素為帶類型變量的類型,就會出現(xiàn)這樣的情況,明明通過了編譯,沒有任何
unchecked warning
,但在運行時卻出錯。所以泛型必須設(shè)計為這個樣子,以保證:如果你的整個應(yīng)用程序在
jdk1.5
下通過了編譯而且沒有
unchecked warning
,那它就是類型安全的。
然而,你還可以用通配符數(shù)組,接下來是以上代碼的兩個改版。
第一個讓數(shù)組類和數(shù)組對象都用了通配符,在最后一句,如果要賦值給
String
,就必須用顯示的類型轉(zhuǎn)換,雖然出了錯,那么可以說這不是機制的錯誤了,而是程序員的錯。
?














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














?
同樣的,試圖創(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é)果以對象集合返回,有一鐘方法就是顯示的使用一個工廠對象,如下:































你可以這樣調(diào)用它:
?
public ?EmpInfo?make()?{?
???return ? new ?EmpInfo();?
}?
}?,?”selection?string”);?
?
或者聲明一個實現(xiàn)
Factory
接口的類
EmpInfoFactory
,

public ?EmpInfo?make()?{?
?? return ? new ?EmpInfo();?
}?
}?
然后這樣調(diào)用它:



?
這兩個辦法的缺點就是,你要么在調(diào)用處寫上羅嗦的工廠類,要么為每個類都寫一個工廠類,在每個調(diào)用的地方傳入一個工廠對象,這看起來也不怎么自然。
用
類名稱字面常量來作為一個工廠對象就很自然,它可以用于反射機制,如果不用泛型,可以這樣寫:
C...ollection emps = sqlUtility.select(EmpInfo.class, ”select * from emps”);
???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á)到目的:

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
的其他幾個簡易的新特色會比較有趣些。