清单 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!源代码根本没有包含任何数据类型转换,怎么会这样呢?事实证实编译器确实在编译阶段将数据类型转换插入到代码中,这样做是为了解决类型擦除会降低某些表达式的类型的精度这一事实。这些数据类型转换被期望能够成功,但在本例中却没有成功。