Java 7 中泛型类变量访问的更改

问题描述 投票:0回答:3

这里是一些使用 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;
}
  • 为什么不再编译?
  • 这是 Java 6 中的错误吗?如果是这样为什么?
  • 这是 Java 7 中的错误吗?

我在 google 上搜索过 Oracle bug 数据库,但没有找到任何关于此的信息...

java generics java-7 access-modifiers
3个回答
10
投票

§4.9 ...那么交集类型具有与具有空主体的类类型 (§8) 相同的成员、直接超类 Ck 和直接超接口 T1', ..., Tn',在同一包中声明其中出现交叉类型。

根据我对 JLS 部分的理解,您使用类型变量

<T extends Test>
的情况会创建以下交集:

package <the same as of Test>;

class I extends Test {}

因此,当您访问

T
类型的成员时,您实际上访问的是交集类型
I
的成员。由于私有成员永远不会被子类型继承,因此访问此类成员会失败并出现编译错误。另一方面,由于交集是

,因此允许访问包私有(默认)和受保护成员

...在出现交集类型的同一包中声明。


0
投票

请参阅 @pingw33n 的评论以获取答案,但解决此问题的方法是删除嵌套类上的通用参数。除非您的用例中内部和外部 T 可以不同,否则它们是多余的。他们所做的一切都是造成这种悲伤的原因。


0
投票

解决此问题的方法是将泛型实例转换为声明私有字段的具体超类型,例如

public int get(TestContainer<T> container){
  T t = container.get();
  return ((Test) t)._myVar;
}
© www.soinside.com 2019 - 2024. All rights reserved.