清單 1. 在靜態上下文中非法引用封閉類型參數 class C< T> { static void m() { T t; }
static class D { C< T> t; } }
當編譯這一代碼時,會生成兩個錯誤:
在靜態方法 m 中非法引用 T 的錯誤 在靜態類 D 中非法引用 T 的錯誤 當定義靜態字段時,情況變得更加復雜。在 JSR-14 和 Tiger 中,在泛型類的所有實例中共享該類中的靜態字段。現在,在 JSR-14 編譯器 1.0 和 1.2 中,假如您在靜態字段聲明中引用類型參數,編譯器不會報錯,但它本應該這么做。字段被共享這一事實很輕易在運行時導致希奇的錯誤,如在不包含數據類型轉換的代碼中出現 ClassCastException。
例如,以下程序將在這兩個版本的 JSR-14 下通過編譯而沒有任何警告:
清單 2. 在靜態字段中對封閉類型參數的有問題的引用 class C< T> { static T member;
C(T t) { member = t; }
T getMember() { return member; }
public static void main(String[] args) { C< String> c = new C< String>("test"); System.out.PRintln(c.getMember().toString()); new C< Integer>(new Integer(1)); System.out.println(c.getMember().toString()); } }
請注重,每次分配類 C 的實例時,都要重新設置靜態字段 member。而且,它被設置成的對象類型取決于 C 的實例的類型!在所提供的 main 方法中,第一個實例 c 是 C< String> 類型。而第二個是 C< Integer> 類型。每當從 c 訪問 member 這一共享靜態字段時,總是假定 member 的類型是 String。但是,在分配了類型為 C< Integer> 的第二個實例之后,member 的類型是 Integer。
運行 C 的 main 方法的結果可能會讓您吃驚 — 它將發出一個 ClassCastException!源代碼根本沒有包含任何數據類型轉換,怎么會這樣呢?事實證實編譯器確實在編譯階段將數據類型轉換插入到代碼中,這樣做是為了解決類型擦除會降低某些表達式的類型的精度這一事實。這些數據類型轉換被期望能夠成功,但在本例中卻沒有成功。