前幾天參加了SUN在大連的暑期免費培訓,主要是介紹了Netbeans集成開發環境和jdk1.5、1.6的一些新的特性。原來很少使用netbeans 來作程序,即使它是sun的產品。主要是因為4.1以前的版本過于garbage.但是參加完這次培訓之后,對其很有信心。這次培訓之后,我對sun的了解更加進了一步。這次培訓的老師是李濤老師和葉亮老師,這兩位老師我還是很佩服的。雖然sun的中國研究院,沒有微軟的那么大的名氣,但是我感覺這個團體還是一個很令人敬佩和挑戰創新的團體。我們無法想象沒有IDE的java編程,雖然在原來的文章中我更鼓勵初學者使用文本編輯工具。
對于J2EE的框架理念我感覺這次沒有進行深入的介紹,或與也是我感覺比較遺憾的一點了。
下面給大家介紹一點JDK1.5種新引入的泛型:
以下代碼摘自java.util包的List接口和Iterator接口的定義:
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
public interface Iterator<E> {
E next();
boolean hasNext();
}
類型參數
與尖括號有關的一些東西是JDK 5引入的新東西, 它們是List和Iterator接口的形式的類型參數(簡稱類型形參)聲明.
而在對泛型聲明List進行調用時(例如: List<Integer>), 所有出現的類型形參(如
E)的地方, 都會被實際的類型參數(簡稱類型實參, 如 Integer)所替換掉.
雖然與C++中的模板機制在形式上很想像, 但必需注意, Java中的泛型聲明決不會在調用時被展成多份副本: 不論是在源碼級, 二進制級, 還是在磁盤或內存中, 都不會被展開!
泛型聲明只會也只需編譯一次, 并生成一個類文件(class文件), 這一點跟普通的類或接口完全一樣.
類型參數其實跟方法或構造器中所用的通常參數相類似. 一個方法中可以聲明它用以處理的形式的值參數, 相似地, 泛型聲明也有其形式的類型參數; 當方法被調用時, 實際參數會替換形式參數, 然后執行方法體, 同樣, 當泛型聲明被調用時, 實際的類型參數會替換掉形式的類型參數.
關于命名約定的備注: 推薦使用精煉而簡明(如, 單個字符)的方式為形式的類型參數命名. 最好避免使用小寫字符, 以便與普通的類或接口的參數相區分開來. 許多宣傳品類型使用 E 表示其元素的類型形參.
先看以下兩行代碼是否合法:
List<String> ls = new ArrayList<String>(); // 1
List<Object> lo = ls; // 2
第一行沒問題, 關鍵在第二行代碼, 大多數人會認為, 一個String的List自然更是一個Object的List, 因此, 第2行沒問題.
好, 接著看以下代碼:
lo.add(new Object()); // 3
String s = ls.get(0); // 4: 試圖將一個Object賦給一個String!
可見, 通過別名lo, 我們能對ls, 一個String的列表, 進行數據操作(特別是插入一個Object), 從而導致ls不僅僅是容納了String對象! 這是Java編譯器不容許的! 編譯時, 第2行會報告一個編譯錯誤的.
通常, 若Foo是Bar的一個子類型(子類或子接口), G是某個泛型聲明, 則G<Foo>并不是G<Bar>的一個子類型.
這一點往往是最難以理解的, 因為它和通常的直觀相左. 在直觀的理解中, 我們實際上假定了集合是不會變動的, 但java語言中則非如此.
假定要輸出一個集合中的所有元素. 以下分別是舊版本及新版本(JDK 1.5)中的寫法:
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);
}}
問題在于, 新版本反而不如舊版本更有用些. 因為舊版本能使用各種類型的集合作為參數, 但新版本則只能使用Collection<Object>. 而正如上節看到的, Collection<Object>并不是其它各種集合的超類型(父類型).
所有集合的超類型應該寫作: Collection<?>, 讀作: collection of unknown(未知集合), 即一個集合, 其元素類型可以與任何類型相匹配. 因此稱這種類型為通配類型.
正確實現上述舊版本的代碼可以這么寫:
void printCollection(Collection<?> c) {
for(Object e : c) {
System.out.println(e);
}}
這時, 可以用任意類型的集合來調用此方法. 注意在方法體中, 仍然從 c 中讀入元素并賦給了Object, 這是沒有錯誤的, 因此不論類型實參是何種集合, 它的元素都是object. 然而, 如果任意給它增加一個object則是不安全的:
Collection<?> c = new ArrayList<String>();
c.add(new Object()); // 編譯時的錯誤
由于我們不知道c的元素類型是什么, 所以不能給它增加一個object. 方法add()接受一個類型E的參數, 而E與集合的元素類型相同. 當類型實參是?時, 它表示未知的類型, 我們傳遞給add的參數必須是這個未知類型的子類型. 不幸的是, 既然類型未知, 也就無法決定其子類型, 于是什么也不能作為其參數. 唯一的例外是null, 因為null是所有類型的一個成員.
另一方面, 如果給了一個List<?>, 我們可以調用get()方法并使用其返回的元素. 雖然返回的元素類型是未知類型, 但它總歸是一個object, 因此將get()返回的元素賦給一個Object類型的變量, 或將其傳遞給一個可接受Object的參數都是安全的.
只有注冊用戶登錄后才能發表評論。 | ||
![]() |
||
網站導航:
博客園
IT新聞
Chat2DB
C++博客
博問
管理
|
||
相關文章:
|
||
| |||||||||
日 | 一 | 二 | 三 | 四 | 五 | 六 | |||
---|---|---|---|---|---|---|---|---|---|
30 | 31 | 1 | 2 | 3 | 4 | 5 | |||
6 | 7 | 8 | 9 | 10 | 11 | 12 | |||
13 | 14 | 15 | 16 | 17 | 18 | 19 | |||
20 | 21 | 22 | 23 | 24 | 25 | 26 | |||
27 | 28 | 29 | 30 | 31 | 1 | 2 | |||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
常用鏈接
留言簿(10)
隨筆分類(95)
- Data Structure && Algorithm (14)
- IBM Tech(8)
- No Category(11)
- Personal Comments(12)
- python(2)
- Simple Java(31)
- SUN Tech(17)
隨筆檔案(97)
- 2009年9月 (1)
- 2008年8月 (1)
- 2008年7月 (2)
- 2008年4月 (3)
- 2008年2月 (2)
- 2008年1月 (1)
- 2007年12月 (3)
- 2007年11月 (3)
- 2007年10月 (7)
- 2007年8月 (2)
- 2007年7月 (5)
- 2007年6月 (1)
- 2007年5月 (8)
- 2007年4月 (15)
- 2007年3月 (9)
- 2007年2月 (2)
- 2007年1月 (3)
- 2006年12月 (6)
- 2006年11月 (2)
- 2006年10月 (5)
- 2006年8月 (2)
- 2006年7月 (5)
- 2006年5月 (9)
文章檔案(10)
相冊
J2ME技術網站
java技術相關
mess
搜索
最新評論

- 1.?re: SWT JFACE .TreeViewer Expand事件及其節點處理方法[未登錄]
-
@求助
非常感謝 解決了問題 - --huhu
- 2.?re: The Fifth Discipline Peter M. Senge(彼得·圣潔)
-
@Scott
- --bc05002@gmail.com
- 3.?re: Java6 MUstang新特性總結(摘錄)
- Thanks for your sharing.I like it very much, thanks!
- --ed hardy
- 4.?re: F3(轉http://blogs.sun.com/chrisoliver/entry/f3)
- 評論內容較長,點擊標題查看
- --runescape gold
- 5.?re: ideas are just a multiplier of execution(copied)
- 評論內容較長,點擊標題查看
- --James07