Изменение поведения javac в JDK 7 относительно доступа к частному члену

Этот код компилируется с помощью javac JDK версии 1.6.0_33-b03-424, но не компилируется с использованием javac JDK версии 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:

Test.java:6: error: i in Test is defined in an inaccessible class or interface
        System.out.println(getClass().cast(o).i);
                                             ^
1 error

Изменение кода для хранения результата getClass.cast() во временной переменной позволяет программе компилироваться без ошибок.

Это легко обойти, но я не могу найти никаких оснований для этого изменения в JLS 7 или упоминания об изменениях, подобных этому в примечаниях к выпуску JDK 7. Существует упоминание об изменении доступа к частным членам параметров типа для общего типа, но это не применимо здесь.

Является ли это регрессией в javac? В настоящее время применяется ограничение, которое ранее не выполнялось?

Ответы

Ответ 1

Ну, я озадачен этим, и единственным объяснением, которое я могу приключить, является соединение двух вещей.

1_ getClass() docs сказать следующее:

Фактический тип результата Class<? extends |X|>, где |X| - это стирание статического типа выражения, на котором getClassназывается.

2_ Одна из несовместимости, введенная в Java 7, Компилятор больше не разрешает доступ к частным членам переменных типа.

Таким образом, компилятор не уверен, что приведение производится к базовому классу или подклассу, и он блокирует доступ к закрытому члену, поскольку, если приведение должно быть назначено подклассу, оно было бы незаконным, даже если оно определено в оригинале родительский класс, как показано в следующем примере:

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{}

Итак, я предполагаю, что это еще один из причуд Java из-за правил, которые имеют больше смысла в более сложных примерах.