javac behavior change in JDK 7 regarding private member access

java, java-7, javac, private-members

Solution

Well, I'm puzzled by this and the only explanation I can adventure is the conjunction of two things.

1_ `getClass()` docs say the following:

The actual result type is `Class<? extends |X|>` where `|X|` is the erasure of the static type of the expression on which `getClass` is called.

2_ One of the incompatibilities introduced in Java 7 is Compiler No Longer Allows Access to Private Members of Type Variables.

So, the compiler is unsure it the cast is made to the base class or a subclass and it blocks accesing a private member, since if the cast were to be assigned to a subclass it would be illegal even if defined in the original parent class, as shown in the following example:

class BaseTest {
    private final int i = 1;

    void test(Object o) {
        if (getClass().isInstance(o)) {                
            TestAccess to = TestAccess.class.cast(o);
            //System.out.println(to.i);  // ERROR: i has private access in BaseTest
        }
    }
}

class TestAccess extends BaseTest{}

So, I guess it's one more of Java quirks due to rules that make more sense in more complex examples.

Problem

This code compiles OK using javac JDK version 1.6.0_33-b03-424, but doesn't compile using javac JDK version 1.7.0_06. ``` public class Test { private final int i = 0; void test(Object o) { if (getClass().isInstance(o)) { System.out.println(getClass().cast(o).i); } } } ``` javac output is: ``` Test.java:6: error: i in Test is defined in an inaccessible class or interface System.out.println(getClass().cast(o).i); ^ 1 error ``` Changing the code to store the result of `getClass.cast()` in a temporary variable allows the program to compile without error. This is easy to work around, but I can't find any rationale for this change in the JLS 7, or any mention of a change like this in the JDK 7 release notes. There is a mention of an access change regarding private members of type parameters to a generic, but that doesn't apply here. Is this a regression in javac? Is it now enforcing a restriction that it wasn't enforcing before?

Original source