Я заметил, что Внешние классы могут обращаться к внутренним классам частных переменных экземпляра. Как это возможно? Вот пример кода, демонстрирующий то же самое:
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??
}
}
Почему такое поведение разрешено?
new ABC().new XYZ()
Ответы:
Внутренний класс - это просто способ четко отделить некоторые функциональные возможности, которые действительно принадлежат исходному внешнему классу. Они предназначены для использования, когда у вас есть 2 требования:
Учитывая эти требования, внутренние классы имеют полный доступ к своему внешнему классу. Поскольку они в основном являются членами внешнего класса, имеет смысл, что они имеют доступ к методам и атрибутам внешнего класса, включая рядовые.
источник
Если вы хотите скрыть закрытые члены вашего внутреннего класса, вы можете определить интерфейс с открытыми членами и создать анонимный внутренний класс, который реализует этот интерфейс. Пример ниже:
источник
x
здесь публикуется, это запрещеноmMember.x
.Внутренний класс (для целей контроля доступа) считается частью содержащего класса. Это означает полный доступ ко всем частным лицам.
Для этого используются синтетические методы, защищенные пакетами: внутренний класс будет скомпилирован в отдельный класс в том же пакете (ABC $ XYZ). JVM не поддерживает этот уровень изоляции напрямую, поэтому на уровне байт-кода ABC $ XYZ будет иметь методы с защитой пакетов, которые внешний класс использует для доступа к закрытым методам / полям.
источник
Правильный ответ появляется на другой вопрос, похожий на этот: почему закрытый член вложенного класса может быть доступен с помощью методов включающего класса?
В нем говорится, что есть определение частного определения области JLS - Определение доступности :
источник
ИМХО важным вариантом использования внутренних классов является фабричный шаблон. Вмещающий класс может подготовить экземпляр внутреннего класса без ограничений доступа и передать экземпляр во внешний мир, где будет обеспечен частный доступ.
В отличие от abyx, объявление статического класса не меняет ограничений доступа к включающему классу, как показано ниже. Также работают ограничения доступа между статическими классами в одном и том же классе. Я был удивлен ...
источник
Ограничения доступа устанавливаются для каждого класса. Метод, объявленный в классе, не может получить доступ ко всем членам экземпляра / класса. Это само собой разумеется, что внутренние классы также имеют беспрепятственный доступ к членам внешнего класса, а внешний класс имеет беспрепятственный доступ к членам внутреннего класса.
Помещая класс в другой класс, вы делаете его тесно связанным с реализацией, и все, что является частью реализации, должно иметь доступ к другим частям.
источник
Логика, лежащая в основе внутренних классов, заключается в том, что если вы создаете внутренний класс во внешнем классе, то это потому, что им нужно будет делиться несколькими вещами, и поэтому для них имеет смысл иметь большую гибкость, чем у «обычных» классов.
Если в вашем случае для классов не имеет смысла видеть внутреннюю работу друг друга - что в основном означает, что внутренний класс мог просто стать обычным классом, вы можете объявить внутренний класс как
static class XYZ
. Использованиеstatic
будет означать, что они не будут совместно использовать состояние (и, напримерnew ABC().new XYZ()
, не будут работать, и вам нужно будет использоватьnew ABC.XYZ()
.Но, если это так, вы должны подумать о том,
XYZ
должен ли действительно быть внутренний класс и что, возможно, он заслуживает своего собственного файл. Иногда имеет смысл создать статический внутренний класс (например, если вам нужен небольшой класс, который реализует интерфейс, используемый вашим внешним классом, и это больше никуда не поможет). Но примерно в половине случаев это должно было быть сделано внешним классом.источник
Тило добавил хороший ответ на ваш первый вопрос «Как это возможно?». Я хотел бы остановиться подробнее на втором заданном вопросе: почему такое поведение разрешено?
Для начала, давайте просто проясним, что это поведение не ограничивается внутренними классами, которые по определению являются нестатическими вложенными типами. Такое поведение разрешено для всех вложенных типов, включая вложенные перечисления и интерфейсы, которые должны быть статическими и не могут иметь включающий экземпляр. По сути, эта модель является упрощением вплоть до следующего утверждения: вложенный код имеет полный доступ к вложенному коду - и наоборот.
Так почему тогда? Я думаю, что пример лучше проиллюстрирует это.
Подумайте о своем теле и своем мозге. Если вы вводите героин в руку, ваш мозг становится все сильнее. Если область миндалины вашего мозга увидит то, что, по его мнению, представляет угрозу для вашей личной безопасности, скажем, например, оса, он заставит ваше тело развернуться и побежать к холмам, чтобы вы не «подумали» об этом дважды.
Таким образом, мозг является неотъемлемой частью тела - и, как ни странно, наоборот. Использование контроля доступа между такими тесно связанными объектами лишает их права на отношения. Если вам нужен контроль доступа, то вам нужно разделить классы по-настоящему на отдельные единицы. До тех пор они единое целое. Движущим примером для дальнейших исследований было бы посмотреть, как
Iterator
обычно реализуется Java .Неограниченный доступ от вложенного кода к вложенному коду делает его по большей части довольно бесполезным для добавления модификаторов доступа к полям и методам вложенного типа. Это добавляет беспорядок и может дать ложное чувство безопасности для новичков в языке программирования Java.
источник
Внутренний класс рассматривается как атрибут Внешнего класса. Следовательно, независимо от того, является ли переменная экземпляра класса Inner частной или нет, Outer класс может получить доступ без каких-либо проблем, точно так же, как и к другим его закрытым атрибутам (переменным).
источник
Потому что ваш
main()
метод находится вABC
классе, который может получить доступ к своему внутреннему классу.источник
ABC
класса получать доступ к классам, вложенным вABC
класс, а в том , почему они могут получить доступ к закрытым членам классов, вложенных вABC
класс в Java.