Java Scoping Rules и внутренние классы - PullRequest
4 голосов
/ 31 января 2011

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

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

Ответы [ 6 ]

17 голосов
/ 31 января 2011

Статические вложенные классы 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 вложенные классы.

3 голосов
/ 31 января 2011

Не знаю, поможет ли это, но из Java-учебников :

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

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

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

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

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

3 голосов
/ 31 января 2011

Вы должны дифференцировать:

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

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

Пример:

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);
}
1 голос
/ 12 апреля 2018

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

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

Метод Scoped внутренних классов: - Доступ только к последним членам внешнего класса.

0 голосов
/ 21 августа 2013

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

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