Changes in access of variables for generic classes

2019-02-08 07:41发布

Here is a simple example of some code that compiles using Java 6, but does not compile in 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;
    }
  }
}

In Java 7, it fails to compile in the get(TestContainer<T> container) method, with the error:

error: _myVar has private access in Test

I don't understand why this no longer compiles - in my mind it should. The variable t is of type T, which must extend Test. It's trying to access the field _myVar of a instance of Test from within the class Test.

Indeed, if I change the method get(TestContainer<T> container) to the following, it compiles (with no warnings):

public int get(TestContainer<T> container){
  Test t = container.get();
  return t._myVar;
}
  • Why does this no longer compile?
  • Was this a bug in Java 6? If so why?
  • Is this a bug in Java 7?

I've had a google and searched in the Oracle bug database, but haven't found anything on this...

3条回答
别忘想泡老子
2楼-- · 2019-02-08 08:02

See @pingw33n's comment for the answer, but the way to fix this is to remove the generic parameters on the nested class. Unless you have a use case where the inner and outer T's can be different, they are redundant. All they are doing is causing this grief.

查看更多
贪生不怕死
3楼-- · 2019-02-08 08:04

§4.9 ... Then the intersection type has the same members as a class type (§8) with an empty body, direct superclass Ck and direct superinterfaces T1', ..., Tn', declared in the same package in which the intersection type appears.

From my understanding of that JLS part, your case with a type variable <T extends Test> creates the following intersection:

package <the same as of Test>;

class I extends Test {}

Therefore when you access members of the type T you actually access members of the intersection type I. Since private members are never inherited by subtypes accessing such member fails with compile-error. On the other hand access to package-private (default) and protected members is allowed by the fact the intersection is

... declared in the same package in which the intersection type appears.

查看更多
地球回转人心会变
4楼-- · 2019-02-08 08:13

A workaround for this is to cast the generic instance to the concrete supertype that declares the private field, e.g.

public int get(TestContainer<T> container){
  T t = container.get();
  return ((Test) t)._myVar;
}
查看更多
登录 后发表回答