J2SE 1.5 ― 代號為“Tiger” ― 計劃在 2003 年年底發布,它將包括泛型型別(如在 JSR-14 原型編譯器中預先展示的那樣,現在可下載獲得)。在 第 1 部分中,我們討論了泛型型別的基礎知識,以及為什麼它們是對 Java 語言的一個重要且迫切需要的補充。我們還說明了為 Tiger 制定的泛型型別的實現怎麼會包含數個“缺陷”,這些缺陷限制了可以使用泛型型別的上下文。
為了協助新程式員有效地使用泛型型別,我將詳細說明到底泛型型別的哪些用法在 Tiger 和 JSR-14 中是被禁止的,並將說明為什麼這些限制是 JSR-14(理所當然還有 Tiger)為了在 JVM 上相容地實現泛型型別所使用的實現策略的必然結果。
泛型型別的限制
讓我們先查閱一下 Tiger 和 JSR-14 中泛型型別的使用限制:
不應在靜態成員中引用封閉型別參數。
不能用基本類型執行個體化泛型型別參數。
不能在資料類型轉換或 instanceof 操作中使用“外露”型別參數。
不能在 new 操作中使用“外露”型別參數。
不能在類定義的 implements 或 extends 子句中使用“外露”型別參數。
為什麼會有這些限制呢?這要歸因於 Tiger 和 JSR-14 為在 JVM 上實現泛型型別所使用的機制。由於 JVM 根本不支援泛型型別,所以這些編譯器“耍了個花招”,使得似乎存在對泛型型別的支援 ― 它們用泛型型別資訊檢查所有的代碼,但隨即“擦除”所有的泛型型別並產生只包含普通類型的類檔案。
例如,將象 List<T> 這樣的泛型型別擦除得只剩下 List 。“外露”型別參數 ― 單獨出現而不是位於某個類型中的型別參數(如類 List<T> 中的型別參數 T )― 被簡單地擦除成它們的上界(就 T 而言,其上界就是 Object )。
這一技術的功能極其強大;我們可以使幾乎所有泛型型別的精度得到增強,但又與 JVM 保持相容。事實上,我們甚至可以交替地使用非泛型的舊類(比如 List )和其對應的泛型類( List<T> );兩者在運行時看起來是一樣的。
遺憾的是,正如以上的限制所示,獲得這一功能是有代價的。以這種方式進行擦除在類型系統中引入了缺陷,這些缺陷限制我們使用泛型型別的安全性。
為了協助說明每種限制,我們查閱會出現這些限制的樣本。在本文中,我們將討論前三個限制。與後兩個限制有關的問題過於複雜,因而需要更深入的研究,留待下一篇文章討論。
靜態成員中的封閉型別參數
編譯器完全禁止在靜態方法和靜態內部類中引用封閉型別參數。所以,舉例來說,以下代碼在 Tiger 中就是非法的:
清單 1. 在靜態上下文中非法引用封閉型別參數
class C<T> {
static void m() {
T t;
}
static class D {
C<T> t;
}
}