Правила области видимости Java и внутренние классы

Все сумасшедшие правила области видимости Java кружат мне голову, а чушь public static void не помогает. До сих пор все языки программирования, которые я использовал, либо лексическая область видимости, либо некоторое ее приближение без каких-либо модификаторов доступа, то есть внутреннее содержимое захватывает внешний материал и имеет доступ к внешнему материалу, пока существует внутренний материал.

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


person David K.    schedule 31.01.2011    source источник
comment
Взгляните на справочную карточку этого сообщения ( внизу статьи), в котором кратко излагаются правила определения объема работ.   -  person Aravind Yarram    schedule 31.01.2011
comment
Пожалуйста (1) приглушите и (2) уточните свой вопрос. «Сумасшедшие правила области видимости Java», о которых вы спрашиваете, идентичны «лексической области видимости», как в C ++. Вам придется объяснить, что вы имеете в виду под бессмыслицей «public static void»: это еще одна функция, которая также существует в C ++. А плавающих вокруг «публичных статических частных» вещей не существует: это просто противоречие в терминах.   -  person user207421    schedule 31.01.2011
comment
Совершенно уверен, что OP исходит из фона языка сценариев с истинной лексической областью видимости (например, JavaScript, Ruby) и меньшим упором на ключевые слова-модификаторы повсюду. Просто говорю.   -  person ide    schedule 31.01.2011
comment
@EJP: Вопрос довольно ясный. Модификаторы доступа взаимодействуют с областью видимости, и неясно, как модификаторы доступа изменяют лексическую область видимости экземпляров и внутренних классов.   -  person David K.    schedule 31.01.2011
comment
@ davidk01: Я не согласен. Он вообще не упоминает модификаторы доступа, только правила области видимости. И «сумасшедший», «вздор» и т. Д. Тоже не вызывают симпатии.   -  person user207421    schedule 31.01.2011
comment
@EJP: я думаю, что «public static void», «public static private» квалифицируются как упоминание модификаторов доступа. Все эти квалификаторы действительно бессмысленны, потому что любой другой язык программирования обходится без них и всех церемониальных заклинаний, которые требует Java. В любом случае я здесь не для того, чтобы спорить с вами о недостатках Java.   -  person David K.    schedule 31.01.2011
comment
@ davidk01: Это тоже считается чушью.   -  person user207421    schedule 31.01.2011
comment
Ваш вопрос ясен, и ваше настроение похоже на человеческое. Мы не машины и не должны действовать как машины.   -  person Markus Siebeneicher    schedule 13.11.2014


Ответы (6)


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

Нестатические вложенные классы (называемые внутренними классами) возникают только в контексте экземпляра внешнего класса. При построении у них автоматически создается второе поле this, к которому вы можете получить доступ из внутреннего класса, используя синтаксис Outer.this. Каждый экземпляр внутреннего класса заключен в единственный экземпляр внешнего класса. Опять же, все права доступа статических вложенных классов применяются к внутренним классам. Но поскольку у них уже есть доступный экземпляр внешнего класса, они могут автоматически обращаться к переменным экземпляра и методам внешнего класса.

Для приятного (и очень подробного) обсуждения внутренних классов и спецификаторов доступа вы можете прочитать Спецификация внутреннего класса. Он описывает, среди прочего, как вложенный класс получает доступ к private членам своего внешнего класса (ов). Более осторожным чтением является руководство по вложенным классам.

Не по теме: предположим, что у вас есть такая структура классов:

public class O {
    public O() { ... }

    public class I { // an inner class
        public I() { ... }
        ...
    }
    ...
}

и вы создали экземпляр O:

O outer = new O();

Теперь предположим, что вы хотите создать экземпляр O.I. вы не можете просто использовать new O.I(), потому что новый экземпляр I должен быть заключен в конкретный экземпляр O. Для этого Java предоставляет следующий синтаксис:

O.I inner = outer.new O.I();

Затем inner будет иметь второе поле this, указанное для ссылки на outer.

Обратите внимание, что этот синтаксис «квалифицированного new оператора» используется только для внутренних классов; это было бы ненужным (фактически, ошибка), если бы I был static вложенным классом.

1 Вы часто будете встречать фразу «статический внутренний класс» (в том числе, к сожалению, в более ранней версии этого ответа). Это неправильная терминология. В Java «внутренние классы» - это конкретно не static вложенные классы.

person Ted Hopp    schedule 31.01.2011
comment
Этот второй абзац является ключевым различием между статическими внутренними классами и внутренними классами экземпляра. - person ide; 31.01.2011
comment
Это довольно ясно. Итак, если я правильно вас понял, любая переменная, объявленная во внешнем классе, независимо от какого-либо модификатора доступа, доступна из нестатического внутреннего класса. Таким образом, все статические и частные переменные и методы во внешних классах доступны из внутреннего класса. - person David K.; 31.01.2011
comment
Вот и все. Если производительность критична, имейте в виду, что внутренний класс имеет небольшой недостаток как во времени, так и в памяти для доступа к защищенным или частным членам внешнего класса (и наоборот). После компиляции внутренние классы (статические или нет) обрабатываются в байтовом коде как отдельные классы. Таким образом, компилятор должен создать функции доступа, чтобы байтовый код подчинялся правилам доступа. - person Ted Hopp; 31.01.2011

Вы должны различать:

  • Статические внутренние классы имеют доступ ко всем статическим членам вне их объявления.
  • Внутренние классы экземпляров имеют доступ ко всем членам класса за пределами их объявления, И к полям final в функции, в которой они объявлены.

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

Пример:

public void doStuff(final int a, int b) {
    final int c; // Can be referenced
    int d;       // Cannot be referenced, not final

    executer.execute( new Runnable() {
        public void run() {
            System.out.println("a: "+a+"  c: "+c);
        }
    }

    b++; // Not final, not referencable
    System.out.println(b);
}
person Daniel    schedule 31.01.2011

Не знаю, помогает ли это, но из руководств по java:

Статические вложенные классы

Как и в случае с методами и переменными класса, статический вложенный класс связан со своим внешним классом. И, как и методы статического класса, статический вложенный класс не может напрямую ссылаться на переменные экземпляра или методы, определенные в его включающем классе - он может использовать их только через ссылку на объект. Примечание. Статический вложенный класс взаимодействует с членами экземпляра своего внешнего класса (и других классов) так же, как и любой другой класс верхнего уровня. Фактически, статический вложенный класс поведенчески является классом верхнего уровня, который был вложен в другой класс верхнего уровня для удобства упаковки.

Внутренние классы [нестатический вложенный класс?]

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

Вам следует проверить руководство по Java по вложенным классам.

person Andre85    schedule 31.01.2011

Правила внутренних классов в Java

  1. В Java можно определить класс внутри другого класса, такие классы называются вложенными классами или внутренним классом.
  2. Существует 3 типа внутренних классов. Экземпляр Внутренний класс, статический внутренний класс и анонимный внутренний класс.
  3. Если внутренний класс объявлен как внутренний класс экземпляра, то он может получить доступ ко всем членам внешнего включающего класса, включая частные члены.
  4. Если внутренний класс объявлен как статический, он может получить доступ только к статическим членам внешнего класса (включая частные статические члены). Но он НЕ может получить доступ к членам экземпляра
  5. Учтите, что существует переменная x, определенная как во внешнем классе, так и во внутренних классах экземпляра, тогда общая форма доступа к переменной из внутреннего класса - this.x для внутреннего x и OuterClassname.this.x для внешнего x.
  6. Вы также можете определить внутренний класс внутри любого метода или любого другого блока.
  7. Общая форма создания экземпляра внутреннего класса извне внешнего класса - Outer.Inner ob = new Outer.new Inner();
  8. Общая форма создания экземпляра внутреннего класса извне внешнего класса (если внутренний класс объявлен как статический) Outer.Inner ob = new Outer.Inner();
  9. Внутренние классы могут быть объявлены с помощью любого из ключевых слов модификатора доступа.
  10. Если внутренний класс объявлен как частный, он НЕ может быть создан извне внешнего класса. Также в этом случае вы НЕ МОЖЕТЕ получить доступ к членам внутреннего класса извне внешнего класса, даже если у вас есть ссылка на объект, и даже если члены частного внутреннего класса объявлены как общедоступные.
  11. Если внутренний класс объявлен как внутренний класс экземпляра, он также может получить доступ к членам суперкласса внешнего класса через общий оператор Outer.super.variable; Outer.super.method(params);
person Vipul Verma    schedule 12.04.2018

Правила для внутреннего класса

  1. Внешний класс, к которому обращается внутренний класс
  2. Внутренний класс недоступен для внешнего класса
  3. Члены внутреннего класса использовали только методы, а члены внутри класса получали доступ только к полной информации.
person user2701769    schedule 21.08.2013

Внутренние классы с областью видимости метода: - Может иметь доступ только к последним членам внешнего класса.

person Shikhar    schedule 07.08.2015