Почему внешние классы Java могут получить доступ к закрытым членам внутреннего класса?
Я заметил, что внешние классы могут получить доступ к внутренним классам частных переменных экземпляра. Как такое возможно? Вот пример кода, демонстрирующий то же:
class ABC{
class XYZ{
private int x=10;
}
public static void main(String... args){
ABC.XYZ xx = new ABC().new XYZ();
System.out.println("Hello :: "+xx.x); ///Why is this allowed??
}
}
почему такое поведение разрешено?
10 ответов:
внутренний класс-это просто способ четко отделить некоторые функции, которые действительно принадлежат исходному внешнему классу. Они предназначены для использования, когда у вас есть 2 требования:
- некоторые функциональные возможности вашего внешнего класса были бы наиболее понятны, если бы они были реализованы в отдельном классе.
- несмотря на то, что он находится в отдельном классе, функциональность очень тесно связана с тем, как работает внешний класс.
учитывая эти требования, внутренние классы имеют полный доступ к их внешнему классу. Поскольку они в основном являются членами внешнего класса, имеет смысл, что они имеют доступ к методам и атрибутам внешнего класса, включая рядовых.
Если вы хотите скрыть закрытые члены внутреннего класса, вы можете определить интерфейс с членами общественных и создать анонимный внутренний класс, который реализует этот интерфейс. Пример ниже:
class ABC{ private interface MyInterface{ void printInt(); } private static MyInterface mMember = new MyInterface(){ private int x=10; public void printInt(){ System.out.println(String.valueOf(x)); } }; public static void main(String... args){ System.out.println("Hello :: "+mMember.x); ///not allowed mMember.printInt(); // allowed } }
внутренний класс (для целей контроля доступа) считается частью содержащего класса. Это означает полный доступ ко всем частникам.
это реализуется с помощью синтетических методов, защищенных от пакетов: внутренний класс будет скомпилирован в отдельный класс в том же пакете (ABC$XYZ). JVM не поддерживает этот уровень изоляции напрямую, так что на уровне байт-кода ABC$XYZ будет иметь защищенные от пакетов методы, которые внешний класс использует для получения частные методы/поля.
есть правильный ответ появляется на другой вопрос, похожий на этот: почему закрытый член вложенного класса может быть доступен с помощью методов заключающего класса?
Он говорит, что есть понятие частной области на JLS-определение доступности:
в противном случае, если элемент или конструктор объявлен закрытым,тогда доступ разрешен, если и только если он происходит в теле класса верхнего уровня (§7.6), который включает объявление члена или конструктора.
важным примером использования IMHO для внутренних классов является фабричный шаблон. Заключающий класс может подготовить экземпляр внутреннего класса без ограничений доступа и передать экземпляр во внешний мир, где будет соблюдаться Частный доступ.
в нарушение abyx объявление класса static не изменяет ограничений доступа к включающему классу, как показано ниже. Также ограничения доступа между статическими классами в одном и том же вложенном классе: рабочий. Я был удивлен ...
class MyPrivates { static class Inner1 { private int test1 = 2; } static class Inner2 { private int test2 = new Inner1().test1; } public static void main(String[] args) { System.out.println("Inner : "+new Inner2().test2); } }
ограничения доступа выполняются на основе каждого класса. Метод, объявленный в классе, не может получить доступ ко всем членам экземпляра/класса. Это означает, что внутренние классы также имеют неограниченный доступ к членам внешнего класса, а внешний класс имеет неограниченный доступ к членам внутреннего класса.
помещая класс внутри другого класса, вы делаете его плотно привязанным к реализации, и все, что является частью реализация должна иметь доступ к другим частям.
логика внутренних классов заключается в том, что если вы создаете внутренний класс во внешнем классе, это потому, что им нужно будет поделиться несколькими вещами, и поэтому для них имеет смысл иметь большую гибкость, чем "обычные" классы.
если в вашем случае нет смысла, чтобы классы могли видеть внутреннюю работу друг друга - что в основном означает, что внутренний класс мог просто быть сделан обычным классом, вы можете объявить внутренний класс как
static class XYZ. Используяstaticбудет означать, что они не разделяют государство (и, напримерnew ABC().new XYZ()не будет работать, и вы должны использоватьnew ABC.XYZ().
Но, если это так, вы должны подумать о том,XYZдействительно должен быть внутренним классом и что, возможно, он заслуживает свой собственный файл. Иногда имеет смысл создать статический внутренний класс (например, если вам нужен небольшой класс, который реализует интерфейс, который использует ваш внешний класс, и это не будет полезно больше нигде). Но примерно в половине случаев это надо было сделать внешний класс.
Тило добавил хороший ответ на ваш первый вопрос "как это возможно?". Я хочу немного остановиться на втором заданном вопросе: почему такое поведение разрешено?
для начала, давайте просто будем совершенно ясно, что это поведение разрешено не только для внутренних классов, которые по определению являются нестатическими вложенными типами. Это поведение разрешено для всех вложенных типов, включая вложенные перечисления и интерфейсы, которые должны быть статическими и не могут иметь заключительный экземпляр. В принципе, модель является упрощением вплоть до следующего утверждения: вложенный код имеет полный доступ к вложенному коду - и наоборот.
Так почему же тогда? Я думаю, что пример лучше иллюстрирует этот момент.
подумайте о своем теле и мозге. Если вы вводите героин в руку, ваш мозг получает высокий. Если область миндалевидного тела вашего мозга видит то, что он считает угрозой вашей личной безопасности, скажем, Оса, например, он заставит ваше тело повернуться в другую сторону и бегите в горы, не" думая " дважды об этом.
Iteratorобычно реализуется.неограниченный доступ от вложенного кода к вложенному коду делает, по большей части, довольно бесполезным добавление модификаторов доступа к полям и методам вложенного типа. Это добавляет беспорядок и может обеспечить ложное чувство безопасности для новых пользователей языка программирования Java.
внутренний класс рассматривается как атрибут внешнего класса. Таким образом, независимо от того, является ли внутренняя переменная экземпляра класса частной или нет, внешний класс может получить доступ без каких-либо проблем, как и доступ к его другим частным атрибутам(переменным).
class Outer{ private int a; class Inner{ private int b=0; } void outMethod(){ a = new Inner().b; } }
Comments