Из спецификации языка Java - 8.5 Объявления типов элементов
Если класс объявляет тип элемента с определенным именем, то объявление этого типа называется скрытымлюбые доступные декларации типов членов с одинаковыми именами в суперклассах и суперинтерфейсах класса.
Класс наследует от своего прямого суперкласса и прямых суперинтерфейсов все не приватные типы членов суперкласса и суперинтерфейсов, которые оба доступны для кода в классе и не скрыты объявлением в классе.
Мы можем сделать вывод, что:
B.Inner
скрывает A.Inner
.B
не наследует A.Inner
.A.Inner
не является членом (8.2) типа B
.C
не может наследовать A.Inner
от B
.C не может наследовать B.Inner
от B
, потому что это личное.
Следовательно, C
не имеет типа члена Inner
.Предположим, что во вложенных областях действия C нет другого типа Inner
(внешний класс; модуль компиляции; пакет), тогда имя типа Inner
не может быть разрешено.
javac
пытается сообщить о более подробной ошибке,но это только предположение, по вашему желанию.Даже лучшее сообщение об ошибке, вероятно, должно включать все вышеприведенные объяснения.
В 1-м примере о Entry
оператор import объявляет Entry
во всей области действия модуля компиляции (т.е. в файле java), поэтому Entry
определяется как Map.Entry
IntelliJ 10.5 не жалуется на 1-й пример;видимо ошибка была исправлена.Это все еще неправильно на втором примере.
В private
есть что-то смешное.Почему спецификация явно исключает private
членов, хотя она уже требует, чтобы члены были "доступны"?На самом деле B.Inner
доступно во всем теле CompileTest
(6.6.1), включая C
.C
может иметь doStuff(B.Inner)
, и он будет компилироваться.
Вероятно, поэтому IntelliJ облажался во втором примере;он считает, что B.Inner
доступен для C
, поэтому C
наследует B.Inner
.Он упустил из виду дополнительное исключение private
членов в наследстве.
Это выявляет 2 противоречивых мнения о сфере действия private
декларации.Представление № 1 хочет, чтобы область действия была непосредственным включающим классом, представление № 2 хочет, чтобы это был класс включения верхнего уровня.# 2 менее известен программистам, они были бы удивлены, узнав, что C
может получить доступ к B.Inner
.№ 2 можно обосновать следующим образом: они все равно находятся в одном файле, поэтому нет необходимости в инкапсуляции, мы никого не защищаем, запрещая доступ;разрешение доступа более удобно в большинстве случаев.
Представление № 2, вероятно, также утверждало, что C
должно наследовать B.Inner
- что может пойти не так?Интересно, что # 2 выигрывает в общем правиле контроля доступа, но проигрывает в правиле наследования.
Спецификация действительно очень грязная, к счастью, мы обычно не сталкиваемся с этими сложными ситуациями.Это скорее ошибка LinkedHashMap
и HashMap
, которые изменяют публичное имя для частного использования.