Why does this code compile in Java 1.6 but not in Java 1.7?

痴心易碎 提交于 2019-12-01 15:02:22

The demonstrated issue seems to match the behavior reported in Oracle bug 6904536. The bug was closed as "Not an Issue" with the following explanation:

javac is behaving according to the JLS. See also 6558551, 6711619 and related JLS issue 6644562.

The corresponding JLS issue is unresolved, with the following comment:

A simplified explanation for the membership of type variables is welcome. There is a general difficulty with private members of a type variable's bounds. Formally such members do not become members of the type variable itself, though javac and Eclipse traditionally made them members and code has come to rely on that:

class Test {
  private int count = 0;
  <Z extends Test> void m(Z z) {
    count = z.count;  // Legal in javac 1.6, illegal in javac 1.7 due to fix for 6711619
  }
}

Peter submitted a similar test:

class A {
  static class B { private String f; }

  abstract static class Builder<T extends B> {
    abstract T getB();

    {
      ((B)getB()).f.hashCode();
      getB().f.hashCode(); // error: f has private access in A.B
    }

  }
}

Since intersection types are constructed by inheritance, and private members are never inherited, it is tricky to re-specify intersection types to have private members. Nonetheless, it would be the compatible thing to do.

For reference, the relevant section of the JLS is §4.4.

EDIT:

I tend to agree with the JLS here actually, because it matches up with itself when we remove generics from the picture. Consider this example:

static class Parent {

    private int i;

    void m(Child child) {
        i = child.i; //compile error
    }
}

static class Child extends Parent { }

child.i isn't visible because access to private members isn't inherited. This point is driven home by the fact that Child can have its own i without any shadowing:

static class Child extends Parent {
    private int i; //totally fine
}

So this would be a rare example of upcasting being necessary:

void m(Child child) {
    i = ((Parent)child).i;
}

So with inherited accessibility out of the picture, the JLS seems correct here, given that the V in Foo<V extends Foo<V>> isn't necessarily Foo<V> but could be some type that extends Foo<V>.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!