Внутренний класс

Материал из Википедии — свободной энциклопедии
Перейти к: навигация, поиск

Внутренний, или вложенный класс (англ. inner class) — в объектно-ориентированном программировании класс, целиком определённый внутри другого класса.

Вложенные классы поддерживаются в языке программирования Java, начиная с версии 1.1, С# и других языках на платформе .NET, а также в языке программирования D и в C++.

Обзор[править | править вики-текст]

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

Внутренние классы в языке Java[править | править вики-текст]

В Java существуют 4 типа вложенных (nested) классов:

Внутренние (нестатические) классы[править | править вики-текст]

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

Внутренние нестатические классы описываются внутри основного внешнего класса. Экземпляры таких классов имеют доступ к public, protected, default и private полям внешнего класса. А также статическим и нестатическим методам внешнего экземпляра с любыми модификаторами доступа. За счёт того, что экземпляры внутреннего класса всегда логически привязаны к экземплярам окружающего класса, они не могут содержать (хотя могут наследовать от предка) определение статических полей, методов и классов (кроме констант).[1]

Пример объявления внутреннего класса:

 1 class OuterClass {
 2     
 3     private int outerField;
 4     
 5     class InnerClass {
 6         int getOuterField() {
 7             return OuterClass.this.outerField; // эта строчка кода демонстрирует концепцию замыкания.
 8         }
 9     }
10     
11 }

Создание описанного класса можно описать следующим блоком кода: OuterClass.InnerClass inner = new OuterClass().new InnerClass();

Статические вложенные классы[править | править вики-текст]

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

Пример объявления вложенного статического класса:

 1 class OuterClass {
 2     
 3     private int outerField;
 4     static int staticOuterField;
 5     
 6     static class StaticInnerClass {
 7         int getOuterField() {
 8             return OuterClass.this.outerField; // эта строчка кода приведёт к ошибке компиляции.
 9         }
10         int getStaticOuterField() {
11             return OuterClass.staticOuterField; // эта строчка кода корректна.
12         }
13     }
14     
15 }

Создание описанного статического вложенного класса можно описать следующим блоком кода: OuterClass.StaticInnerClass staticInner = new OuterClass.InnerClass();

Локальные классы[править | править вики-текст]

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

Пример:

 1 class OuterClass {
 2     
 3     private int outerField;
 4     
 5     void methodWithLocalClass(final int finalParameter) {
 6         int notFinalVar = 0;
 7         notFinalVar++;
 8         
 9         class InnerLocalClass {
10             void getOuterField() {
11                 int a = notFinalVar; // эта строчка кода приведёт к ошибке компиляции. no-final переменные вне контекста недоступны.
12                 int b = OuterClass.this.outerField; // эта строчка кода демонстрирует обращение члену обрамляющего класса.
13             }
14             
15             int getParameter() {
16                 return finalParameter; // эта строчка кода демонстрирует обращение к final переменной вне контекста.
17             }
18         }
19     }
20 }

Создание описанного локального класса возможно только внутри самого метода строго ниже кода объявления самого класса. Пример кода создания: InnerLocalClass innerLocal = InnerLocalClass();

Анонимные (безымянные) классы[править | править вики-текст]

Декларируются внутри методов основного класса. Могут быть использованы только внутри этих методов. В отличие от локальных классов, анонимные классы не имеют названия. Главное требование к анонимному классу - он должен наследовать существующий класс или реализовывать существующий интерфейс. Не могут содержать определение (но могут наследовать) статических полей, методов и классов (кроме констант). Пример:

 1 class OuterClass {
 2     
 3     /** 
 4     *   При определении анонимного класса применен полиморфизм — переменная listener 
 5     *   содержит экземпляр анонимного класса, реализующего существующий 
 6     *   интерфейс ActionListener.
 7     **/
 8     void methodWithAnonymousClass(final int interval) {
 9         ActionListener listener = new ActionListener() {
10             public void actionPerformed(ActionEvent event) {
11                 System.out.println("Эта строка выводится на экран каждые " + interval + " секунд.");
12             }  
13         };
14     
15         Timer t = new Timer(interval, listener); // объект анонимного класса использован внутри метода.
16         t.start();
17     }
18     
19 }

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

 1 // Pre PHP 7 code
 2 class Logger
 3 {
 4     public function log($msg)
 5     {
 6         echo $msg;
 7     }
 8 }
 9 
10 $util->setLogger(new Logger());
11 
12 // PHP 7+ code
13 $util->setLogger(new class {
14     public function log($msg)
15     {
16         echo $msg;
17     }
18 });

См. также[править | править вики-текст]

Литература[править | править вики-текст]

Cay S. Horstmann and Gary Cornell, Core Java, eighth edition (Volume I). Prentice Hall, 2003. ISBN 978-0132354769 (ссылка на страницу книги)

Примечания[править | править вики-текст]

  1. Oracle. The Java™ Tutorials. Inner classes. Oracle Documentation.
  2. Local Classes (The Java™ Tutorials > Learning the Java Language > Classes and Objects). docs.oracle.com. Проверено 12 апреля 2016.

Ссылки[править | править вики-текст]