这里是一些使用 Java 6 编译但不能在 Java 7 中编译的代码的简单示例。
public class Test<T extends Test> {
private final int _myVar;
public Test(int myVar) {
_myVar = myVar;
}
public int get(TestContainer<T> container){
T t = container.get();
return t._myVar;
}
private static class TestContainer<T extends Test> {
private final T _test;
private TestContainer(T test) {
_test = test;
}
public T get(){
return _test;
}
}
}
在Java 7中,在
get(TestContainer<T> container)
方法中编译失败,错误:
错误:_myVar 在测试中具有私有访问权限
我不明白为什么这不再编译 - 在我看来它应该。变量
t
的类型为 T
,它必须扩展 Test
。它试图从类 _myVar
中访问 Test
实例的字段 Test
。
确实,如果我将方法
get(TestContainer<T> container)
更改为以下内容,它将编译(没有警告):
public int get(TestContainer<T> container){
Test t = container.get();
return t._myVar;
}
我在 google 上搜索过 Oracle bug 数据库,但没有找到任何关于此的信息...
§4.9 ...那么交集类型具有与具有空主体的类类型 (§8) 相同的成员、直接超类 Ck 和直接超接口 T1', ..., Tn',在同一包中声明其中出现交叉类型。
根据我对 JLS 部分的理解,您使用类型变量
<T extends Test>
的情况会创建以下交集:
package <the same as of Test>;
class I extends Test {}
因此,当您访问
T
类型的成员时,您实际上访问的是交集类型 I
的成员。由于私有成员永远不会被子类型继承,因此访问此类成员会失败并出现编译错误。另一方面,由于交集是 ,因此允许访问包私有(默认)和受保护成员
...在出现交集类型的同一包中声明。
请参阅 @pingw33n 的评论以获取答案,但解决此问题的方法是删除嵌套类上的通用参数。除非您的用例中内部和外部 T 可以不同,否则它们是多余的。他们所做的一切都是造成这种悲伤的原因。
解决此问题的方法是将泛型实例转换为声明私有字段的具体超类型,例如
public int get(TestContainer<T> container){
T t = container.get();
return ((Test) t)._myVar;
}