17

下面是一些使用 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实例的字段。TestTest

事实上,如果我将方法更改get(TestContainer<T> container)为以下,它会编译(没有警告):

public int get(TestContainer<T> container){
  Test t = container.get();
  return t._myVar;
}
  • 为什么这不再编译?
  • 这是 Java 6 中的错误吗?如果是,为什么?
  • 这是 Java 7 中的错误吗?

我有一个谷歌并在 Oracle 错误数据库中搜索,但没有找到任何关于此的...

4

3 回答 3

10

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

根据我对 JLS 部分的理解,您使用类型变量的情况<T extends Test>会创建以下交集:

package <the same as of Test>;

class I extends Test {}

因此,当您访问类型的成员时,T您实际上访问的是交集类型的成员I。由于访问此类成员的子类型永远不会继承私有成员,因此会因编译错误而失败。另一方面,由于交集是允许的,因此可以访问包私有(默认)和受保护的成员

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

于 2012-05-29T12:16:10.670 回答
0

一种解决方法是将通用实例转换为声明私有字段的具体超类型,例如

public int get(TestContainer<T> container){
  T t = container.get();
  return ((Test) t)._myVar;
}
于 2014-03-14T22:27:43.737 回答
0

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

于 2012-05-29T03:46:18.483 回答