Вложенные классы

Вложенные и внутренние классы в Java

Внутренним классом называют класс, который является членом другого класса. Существует четыре базовых типа внутренних классов в Java:

  1. Nested Inner classes (вложенные внутренние классы)

  2. Static Nested classes or Member of outer class (статические вложенные классы)

  3. Method Local Inner classes (внутренние классы в локальном методе)

  4. Anonymous Inner classes (анонимные классы)

1. Nested Inner classes

Вложенный внутренний класс может получить доступ к любому приватному полю или методу экземпляра внешнего класса. Вложенный внутренний класс может иметь любой модификатор доступа (private, packageprivate, protected, public). Так же как и классы, интерфейсы могут быть вложенными и иметь модификаторы доступа.

Следующий пример демонстрирует использование вложенного внутреннего класса:

Вывод:

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

Например, следующий код не скомпилируется:

Вывод:

Интерфейсы могут так же быть вложенными, и они имеют некоторые интересные особенности. Мы будем рассматривать вложенные интерфейсы в следующем посте.

2. Static Nested classes or Member of outer class

Статические вложенные классы технически не являются внутренними классами. По сути, они представляют собой члены внешнего класса.

Вывод:

3. Method Local Inner classes

Внутренний класс может быть объявлен внутри метода или блока инициализации внешнего класса.

В следующем примере, внутренний класс расположен в методе outerMethod():

Вывод:

Внутренний класс в локальном методе не может использовать локальные переменные внешнего метода до тех пор, пока локальная переменная не будет объявлена как финальная (final).

Например, следующий код сгенерирует ошибку компиляции (обратите внимание, что x не является финальной в outerMethod(), но innerMethod() путается получить к ней доступ):

Вывод:

Но следующий код компилируется и выполняется без проблем (обратите внимание, что x на этот раз финальная):

Вывод:

Основная причина, по которой необходимо объявлять локальную переменную как финальную заключается в том что, локальная переменная живёт в стеке до тех пор, пока метод находится в стеке. А в случае использования внутреннего класса возможна ситуация, когда экземпляр внутреннего класса живёт в куче и после выхода из метода, но ему может быть необходим доступ к переменной, объявленной в методе. Для этого, компилятор может сохранить копию локальной переменной, которая объявлена как финальная, в поле внутреннего класса для дальнейшего использования.

[Внесено уточнение от переводчика. Источник информации: https://en.wikipedia.org/wiki/Final_(Java)]

Внутренний класс в локальном методе не может быть помечен как private, protected, static и transient, но может быть помечен как abstract и final, но не оба одновременно.

4. Anonymous Inner classes

Анонимные внутренние классы объявляются без указания имени класса. Они могут быть созданы двумя путями:

  1. Как наследник определённого класса
    Вывод:

    В коде выше, класс Demo является суперклассом, от которого наследуется анонимный класс, и оба они имеют метод show(). В анонимном классе метод show() будет переопределён.

  2. Как реализация определённого интерфейса
    Вывод:
     

    В коде выше мы создаём объект анонимного внутреннего класса, но этот анонимный внутренний класс является реализацией интерфейса Hello.

    Любой анонимный внутренний класс может за один раз реализовать только один интерфейс. Так же, за один раз можно либо расширить класс, либо реализовать интерфейс, но не одновременно.

    [Статья основана на статье Pawan Kumar. Перевод статьи Олег Родин aka Incretio.

    Оригинал статьи http://www.geeksforgeeks.org/inner-class-java/]

    Примеры кода из статьи:

    https://www.dropbox.com/s/dr6zqdlvthenq86/innerclasses.rar?dl=0

    Примеры кода от переводчика:

    https://www.dropbox.com/s/nuwfkvdzfyrii72/InnerClassesDemo.java?dl=0

 

  • Yura Shevchenko

    отлично написано и очень понятные примеры

  • Юра

    Спасибо, хороший материал.
    Пишите еще!