java泛型契约_还谈java2的泛型以及泛型与静态方法( 转)

还谈java2的泛型以及泛型与静态方法

2007/10/07 12:08 P.M.

静态成员中的封闭类型参数

编译器完全禁止在静态方法和静态内部类中引用封闭类型参数。所以,举例来说,以下代码在 Tiger 中就是非法的:

清单 1. 在静态上下文中非法引用封闭类型参数

class C {

static void m() {

T t;

}

static class D {

C t;

}

}

当编译这一代码时,会生成两个错误:

在静态方法 m 中非法引用 T 的错误

在静态类 D 中非法引用 T 的错误

当定义静态字段时,情况变得更加复杂。在 JSR-14 和 Tiger 中,在泛型类的所有实例中共享该类中的静态字段。现在,在 JSR-14 编译器 1.0 和 1.2 中,如果您在静态字段声明中引用类型参数,编译器不会报错,但它本应该这么做。字段被共享这一事实很容易在运行时导致奇怪的错误,如在不包含数据类型转换的代码中出现 ClassCastException 。

例如,以下程序将在这两个版本的 JSR-14 下通过编译而没有任何警告:

清单 2. 在静态字段中对封闭类型参数的有问题的引用

class C {

static T member;

C(T t) { member = t; }

T getMember() { return member; }

public static void main(String[] args) {

C c = new C("test");

System.out.println(c.getMember().toString());

new C(new Integer(1));

System.out.println(c.getMember().toString());

}

}

请注意,每次分配类 C 的实例时,都要重新设置静态字段 member 。而且,它被设置成的对象类型取决于 C 的实例的类型!在所提供的 main 方法中,第一个实例 c 是 C 类型。而第二个是 C 类型。每当从 c 访问 member 这一共享静态字段时,总是假定 member 的类型是 String 。但是,在分配了类型为 C 的第二个实例之后, member 的类型是 Integer 。

运行 C 的 main 方法的结果可能会让您吃惊 ― 它将发出一个 ClassCastException

!源代码根本没有包含任何数据类型转换,怎么会这样呢?事实证明编译器确实在编译阶段将数据类型转换插入到代码中,这样做是为了解决类型擦除会降低某些表

达式的类型的精度这一事实。这些数据类型转换 被期望能够成功,但在本例中却没有成功。

应该认为 JSR-14 1.0 和 1.2 的这一特殊“功能”是个错误。它破坏了类型系统的健全性,或者可以说,它破坏了类型系统应该和程序员达成的“基本契约”。象对静态方法和类所做的那样,只要防止程序员在静态字段中引用泛型类型,情况就会好很多。

请注意允许这种有潜在“爆炸性”的代码存在所带来的问题并不是程序员 有意在自己的代码中覆盖类型系统。问题是程序员可能会无意中编写这样的代码(比如,由于“复制和粘贴”操作,错误地在字段声明中包括静态修饰符)。

类型检查器应该能帮助程序员从这些类型的错误中恢复,但对于静态字

段而言,类型系统实际上会使程序员更迷惑。当未使用数据类型转换的代码中显示的唯一错误就是 ClassCastException

时,我们应如何诊断这样的错误?对于不清楚 Tiger

中泛型类型所用的实现方案而又恰好假定类型系统合理运行的程序员而言,情况更糟。因为在这样的情况下,类型系统不是合理地运行。

幸运的是,JSR-14 的最新版本(1.3)宣布在静态字段中使用类型参数是不合法的。因此,我们有理由期待在 Tiger 的静态字段中使用类型参数也是不合法的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值