В этом уроке мы изучим вложенные и внутренние классы в Java.
Синтаксис языка Java позволяет нам объявлять классы внутри другого класса, такие классы называются внутренними или вложенными.
Синтаксис
class OuterClass < . class NestedClass < . >>
Вложенные классы делятся на два вида: статические и не статические. Вложенные классы, объявленные как статические называются вложенными статическими (static nested classes). Не статические называются внутренними (inner classes).
class OuterClass < . static class StaticNestedClass < . >class InnerClass < . >>
Вложенные классы — элементы содержащего их класса. Не статические классы имеют доступ к полям содержащего класса, даже если они объявлены как private. Статические — не имеют доступ к членам внешнего класса. Как и другие поля класса, вложенные классы могут быть объявлены как private, public, protected, или package private.
Для чего использовать вложенные классы
Вот некоторые причины использования вложенных классов:
Уроки Java для начинающих | #13 — Создание класса и объекта
- Это хороший способ группировки классов, которые используются только в одном месте: если класс полезен только для одного другого класса, то логично будет держать их вместе. Вложение таких вспомогательных классов делает код более удобным.
- Инкапсуляция: допустим, есть два класса A и B, классу B требуется доступ к свойству класса A, которое может быть приватным. Вложение класса B в класс A решит эту проблему, более того сам класс B можно скрыть от внешнего использования.
- Улучшение читаемости и обслуживаемости кода: вложение малых классов в более высокоуровневые классы позволяет хранить код там, где он используется.
Вложенные классы
Как статические переменные и методы, вложенный (статический) класс связан с внешнимклассом. И так же как и статические методы не может напрямую обращаться к полям объекта внешнего класса.
Доступ к вложенному классу осуществляется с помощью следующей конструкции:
OuterClass.StaticNestedClass
Синтаксис создания объекта вложенного класса:
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
Внутренние классы
Внутренние (не статические) классы, как переменные и методы связаны с объектом внешнего класса. Внутренние классы так же имеют прямой доступ к полям внешнего класса. Такие классы не могут содержать в себе статические методы и поля.
Внутренние классы не могут существовать без экземпляра внешнего. Для создания объекта:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Пример
Рассмотрим внутренний класс в действии. В следующем примере, мы создадим массив, заполним целыми числами и выведем только числа с четными индексами в порядке возрастания.
Структура следующей программы:
- Внешний класс DataStructure с конструктором для создания и заполнения массива и методом для вывода элементов с четными индексами.
- Внутренний класс EvenIterator , который реализует интерфейс DataStructureIterator , который наследует интерфейс Iterator. Итераторы используются для доступа к элементам различных структур данных. Они обычно имеют методы для проверки последнего элемента, получения текущего и следующего элементов.
- Метод main , который создает объект DataStructure ( ds ) и вызывает метод printEven для вывода элементов с четными индексами.
public class DataStructure < private final static int SIZE = 15; private int[] arrayOfInts = new int[SIZE]; public DataStructure() < for (int i = 0; i < SIZE; i++) < arrayOfInts[i] = i; >> public void printEven() < DataStructureIterator iterator = this.new EvenIterator(); while (iterator.hasNext()) < System.out.print(iterator.next() + » «); >System.out.println(); > interface DataStructureIterator extends java.util.Iterator < >private class EvenIterator implements DataStructureIterator < private int nextIndex = 0; public boolean hasNext() < return (nextIndex public Integer next() < Integer retValue = Integer.valueOf(arrayOfInts[nextIndex]); nextIndex += 2; return retValue; >> public static void main(String s[]) < DataStructure ds = new DataStructure(); ds.printEven(); >>
0 2 4 6 8 10 12 14
Обратите внимание, что класс EvenIterator напрямую обращается к полю arrayOfInts класса DataStructure .
Затенение (shadowing)
Если вы объявляете переменную (будь то параметр или свойство класса) в какой-либо области (например, вложенный класс или область метода) с именем уже занятым в данной области, то такое объявление «затеняет» предыдущее и вы не сможете обращаться напрямую к переменной по её имени. Следующий пример демонстрирует эту ситуацию:
public class ShadowTest < public int x = 0; class FirstLevel < public int x = 1; void methodInFirstLevel(int x) < System.out.println(«x = » + x); System.out.println(«this.x = » + this.x); System.out.println(«ShadowTest.this.x = » + ShadowTest.this.x); >> public static void main(String. args) < ShadowTest st = new ShadowTest(); ShadowTest.FirstLevel fl = st.new FirstLevel(); fl.methodInFirstLevel(23); >>
Этот код выведет следующее:
x = 23 this.x = 1 ShadowTest.this.x = 0
В этом примере объявлено три переменные с именем x: поле класса ShadowTest , поле внутреннего класса FirstLevel , и параметр метода methodInFirstLevel . Переменная объявленная как параметр функции methodInFirstLevel затеняет поле внутреннего класса FirstLevel . Следовательно при использовании переменной x в методе methodInFirstLevel , будет использоваться значение переданного параметра. Для обращения к полю класса FirstLevel , используйте ключевое слово this :
System.out.println(«this.x = » + this.x);
Для использования поля x внешнего класса необходимо использовать конструкцию:
System.out.println(«ShadowTest.this.x = » + ShadowTest.this.x);
На этом всё! В следующей части мы рассмотрим еще два типа внутренних классов: локальные и анонимные классы.
Источник: easy-code.ru
Вложенные классы
Вложенные или внутренние классы (inner class) — это классы определенные внутри другого класса. Область действия вложенного класса ограничена областью действия внешнего класса. Если класс В определен в классе А, то класс B не может существовать независимо от класса А. Вложенный класс имеет доступ к членам (в том числе закрытым) того класса, в который он объявлен.
Типы вложенных классов:
- Обычный внутренний класс (regular inner class or member class).
- Локальный класс (method-local inner class).
- Анонимный класс (anonymous inner class).
- Статический вложенный класс (static nested class).
1. Обычный внутренний класс
Внутренний класс определяется в области действия внешнего класса.
Чтобы создать объект внутреннего класса, должен существовать объект внешнего класса.
Внутренний и внешний класс имеют доступ ко всем членам класса друг друга (даже private ).
Следующий пример демонстрирует объявление обычного внутреннего класса:
public class Town < private String postCode = «33333»; public class Street < private int house; public void printAddress() < System.out.println(«Город » + Town.this); System.out.println(«Индекс » + postCode); System.out.println(«Улица » + this); System.out.println(«Дом » + house); >> public void createStreet() < Street street = new Street(); street.house = 78; street.printAddress(); >public static void main(String[] args) < Town town = new Town(); town.createStreet(); Town.Street street1 = town.new Street(); Town.Street street2 = new Town().new Street(); street1.printAddress(); street2.printAddress(); >>
Внутри метода внешнего класса, объект внутреннего класса создается как обычно:
Street street = new Street();
Если мы создаем объект внутреннего класса не в методах внешнего класса или в статических методах внешнего класса, необходимо использовать объект внешнего класса:
new Town().new Street();
town.new Street();
Если необходимо получить ссылку на внутренний класс во внутреннем классе, используем слово this :
System.out.println(«Street is » + this);
Если необходимо получить ссылку на объект внешнего класса, запишите имя внешнего класса, за которым следует точка, а затем ключевое слово this :
System.out.println(«Town is » + Town.this);
Обычный внутренний класс является таким же членом внешнего класса, как и переменные и методы. Следующие модификаторы могут быть применены к обычному внутреннему классу:
- final
- abstract
- public
- private
- protected
- static – но static преобразует его во вложенный класс
- strictfp
Если метод описан как strictfp (явно либо неявно), то JVM гарантирует, что результаты вычисления выражений с double и float в пределах метода будут одинаковыми на всех платформах. Модификатор strictfp для класса и интерфейса указывает на то, что все методы класса/интерфейса будут strictfp .
2. Локальный класс Java
Локальный класс (local class) определяется в блоке Java кода. На практике чаще всего объявление происходит в методе некоторого другого класса. Как и member классы, локальные классы ассоциируются с экземпляром внешнего класса и имеют доступ к его полям и методам.
Локальный класс может обращаться к локальным переменным и параметрам метода, если они объявлены с модификатором final или являются effective final (начиная с Java 8).
Effective final переменная это переменная, которая не объявлена явно как final , но ее значение не меняется.
Экземпляр класса может быть создан внутри того же метода, что и класс, но ниже объявления класса.
Локальные классы не могут быть объявлены как private , public , protected или static .
Они не могут иметь внутри себя статических объявлений (полей, методов, классов). Исключением являются константы ( static final ).
Локальные классы могут быть объявлены как abstract или final .
Рассмотрим пример объявления локального класса:
public class Town2 < private String postCode = «33333»; public void createAddress() < final int houseNumber = 34; class Street < public void printAddress() < System.out.println(«PostCode is » + postCode); System.out.println(«House Number is » + houseNumber); >> Street street = new Street(); street.printAddress(); > public static void main(String[] args) < Town2 town = new Town2(); town.createAddress(); >>
Если локальный класс объявлен внутри статического метода, он имеет доступ только к статическим переменным класса:
public class Town3 < private static String postCode = «33333»; public static void createAddress() < final int houseNumber = 34; class Street < public void printAddress() < System.out.println(«PostCode is » + postCode); System.out.println(«House Number is » + houseNumber); >> Street street = new Street(); street.printAddress(); > public static void main(String[] args) < Town3.createAddress(); >>
3. Анонимный класс
Анонимный класс (anonymous class) — это локальный класс без имени.
Используется тогда, когда нужно переопределить метод класса или интерфейса. Класс одновременно объявляется и инициализируется.
Они могут быть объявлены не только в методе, но и внутри аргумента метода.
Рассмотрим пример анонимного класса:
Анонимный класс может не только переопределить методы класса наследника, но и добавить новые методы. Но новые методы НЕ могут быть вызваны извне анонимного класса:
Случаи использования анонимного класса:
- Тело класса является очень коротким.
- Нужен только один экземпляр класса.
- Класс используется в месте его создания или сразу после него.
- Имя класса не важно и не облегчает понимание кода.
Анонимный класс могут также расширять интерфейс:
4. Статический вложенный класс
Статический вложенный класс (static nested class) – это внутренний класс объявленный с модификатором static .
Статический вложенный класс не имеет доступа к нестатическим полям и методам внешнего класса. Доступ к нестатическим полям и методам может осуществляться только через ссылку на экземпляр внешнего класса. В этом плане static nested классы очень похожи на любые другие классы верхнего уровня.
Рассмотрим примеры объявления статических вложенных классов:
public class Town4 < public static class Street < public void go() < System.out.println(«Go to the Street.»); >> > public class City < public static class District < public void go() < System.out.println(«Go to the District.»); >> public static void main(String[] args) < Town4.Street street = new Town4.Street(); street.go(); District district = new District(); district.go(); >>
Источник: www.examclouds.com
Вложенные и внутренние классы
В Java, подобно методам, переменные класса тоже могут иметь в качестве своего члена другой класс. В Java допускается написание класса внутри другого. Класс, написанный внутри, называется в Java вложенным классом, а класс, который содержит внутренний класс, называется внешним классом.
Синтаксис
Ниже приведен синтаксис для записи вложенного класса. Здесь класс Outer_Demo – это внешний класс, а класс Inner_Demo – вложенный класс.
class Outer_Demo < class Nested_Demo < >>
Вложенные классы в Java делятся на два типа:
- Нестатические вложенные классы – нестатические члены класса.
- Статические вложенные классы – статические члены класса.
Внутренние классы (нестатические вложенные классы)
Внутренние классы — это механизм безопасности в Java. Мы уже знаем, что класс не может быть связан с модификатором доступа private, но если у нас есть класс как член другого класса, то внутренний класс может быть private. И это также используется для доступа к закрытым (private) членам класса.
В Java внутренние классы имеют три типа в зависимости от того, как и где Вы их определяете:
- внутренний класс;
- локальный метод внутреннего класса;
- анонимный внутренний класс.
Внутренние классы
Создать внутренний класс в Java довольно просто. Вам просто нужно написать класс внутри класса. В отличие от класса, внутренний класс может быть закрытым (private), и после того, как Вы объявляете внутренний класс закрытым, он не может быть доступен из объекта вне класса.
Ниже приведен пример создания внутреннего класса и получения доступа к нему. В данном примере мы делаем внутренний класс private и получаем доступ к классу с помощью метода.
Пример
class Outer_Demo < int num; // Внутренний класс private class Inner_Demo < public void print() < System.out.println(«Это внутренний класс»); >> // Доступ к внутреннему классу из метода void display_Inner() < Inner_Demo inner = new Inner_Demo(); inner.print(); >> public class My_class < public static void main(String args[]) < // Создание внешнего класса Outer_Demo outer = new Outer_Demo(); // Доступ к методу display_Inner() outer.display_Inner(); >>
Здесь Вы можете заметить, что Outer_Demo – внешний класс, Inner_Demo – внутренний класс, display_Inner() – метод, внутри которого мы создаем внутренний класс, и этот метод вызывается из основного метода.
Если Вы скомпилируете и выполните вышеуказанную программу, Вы получите следующий результат:
Это внутренний класс
Доступ к частным (private) членам
Как упоминалось ранее, внутренние классы также используются в Java для доступа к закрытым членам класса. Предположим, у класса есть private члены. Для доступа к ним напишите в нем внутренний класс, верните частные члены из метода внутри внутреннего класса, скажем, методом getValue() и, наконец, из другого класса (из которого Вы хотите получить доступ к закрытым членам) вызовите метод getValue() внутреннего класса.
Чтобы создать экземпляр внутреннего класса, сначала Вам необходимо создать экземпляр внешнего класса. После этого, используя объект внешнего класса, Вы можете создать экземпляр внутреннего класса.
Outer_Demo outer = new Outer_Demo(); Outer_Demo.Inner_Demo inner = outer.new Inner_Demo();
Следующий пример показывает, как получить доступ к закрытым членам класса с использованием внутреннего класса.
Пример
class Outer_Demo < // Частная переменная внешнего класса private int num = 2018; // Внутренний класс public class Inner_Demo < public int getNum() < System.out.println(«Это метод getnum внутреннего класса»); return num; >> > public class My_class2 < public static void main(String args[]) < // Создание внешнего класса Outer_Demo outer = new Outer_Demo(); // Создание внутреннего класса Outer_Demo.Inner_Demo inner = outer.new Inner_Demo(); System.out.println(inner.getNum()); >>
Если Вы скомпилируете и выполняете вышеуказанную программу, то получите следующий результат:
Это метод getnum внутреннего класса 2018
Локальный метод внутреннего класса
В Java мы можем написать класс внутри метода, и это будет локальный тип. Как и локальные переменные, возможности внутреннего класса ограничены в рамках метода.
Локальный метод внутреннего класса может быть создан только внутри метода, где определяется внутренний класс. Следующая программа показывает, как использовать локальный внутренний метод.
Пример
public class Outerclass < // Метод экземпляра внешнего класса void my_Method() < int num = 888; // Локальный метод внутреннего класса class MethodInner_Demo < public void print() < System.out.println(«Это метод внутреннего класса: » + num); >> // Конец внутреннего класса // Доступ к внутреннему классу MethodInner_Demo inner = new MethodInner_Demo(); inner.print(); > public static void main(String args[]) < Outerclass outer = new Outerclass(); outer.my_Method(); >>
Получим следующий результат:
Это метод внутреннего класса: 888
Анонимные внутренние классы в Java
Анонимный внутренний класс — это внутренний класс, объявленный без имени класса. В случае анонимных внутренних классов в Java мы объявляем и создаем их в одно и то же время. Как правило, они используются всякий раз, когда Вам необходимо переопределить метод класса или интерфейса. Синтаксис анонимного внутреннего класса в Java выглядит следующим образом:
Синтаксис
AnonymousInner an_inner = new AnonymousInner() < public void my_method() < . . >>;
Пример
Следующая программа показывает, как переопределить метод класса с использованием анонимного внутреннего класса.
abstract class AnonymousInner < public abstract void mymethod(); >public class Outer_class < public static void main(String args[]) < AnonymousInner inner = new AnonymousInner() < public void mymethod() < System.out.println(«Это пример анонимного внутреннего класса»); >>; inner.mymethod(); > >
Получим следующий результат:
Это пример анонимного внутреннего класса
Точно так же Вы можете переопределить методы конкретного класса, а также интерфейс, используя в Java анонимный внутренний класс.
Анонимный внутренний класс как аргумент
Как правило, если метод принимает объект интерфейса, абстрактный класс или конкретный класс, то мы можем реализовать интерфейс, расширить абстрактный класс и передать объект методу. Если это класс, мы можем напрямую передать его методу.
Но во всех трех случаях Вы можете в Java передать анонимный внутренний класс методу. Синтаксис передачи анонимного внутреннего класса в качестве аргумента метода:
Синтаксис
obj.my_Method(new My_Class() < public void Do() < . . >>);
Пример
Следующая программа показывает, как передать анонимный внутренний класс в качестве аргумента метода.
// Интерфейс interface Message < String greet(); >public class My_class < // Метод, который принимает объект интерфейса Message public void displayMessage(Message m) < System.out.println(m.greet() + «, это пример анонимного внутреннего класса в качестве аргумента»); >public static void main(String args[]) < // Создание класса My_class obj = new My_class(); // Передача анонимного внутреннего класса в качестве аргумента obj.displayMessage(new Message() < public String greet() < return «Привет»; >>); > >
Если Вы скомпилируете и выполните вышеуказанную программу, то получите следующий результат:
Привет, это пример анонимного внутреннего класса в качестве аргумента
Статический вложенный класс в Java
Статический внутренний класс — это вложенный класс, который является статическим членом внешнего класса. Доступ к нему возможен без создания экземпляра внешнего класса с использованием других статических элементов. Как и статические члены, статический вложенный класс не имеет доступа к переменным экземпляра и методам внешнего класса. Синтаксис статического вложенного класса в Java выглядит следующим образом:
Синтаксис
class MyOuter < static class Nested_Demo < >>
Пример
Создание экземпляра статического вложенного класса немного отличается от экземпляра внутреннего класса. Следующая программа показывает, как использовать статические вложенные классы.
public class Outer < static class Nested_Demo < public void my_method() < System.out.println(«Это мой вложенный класс»); >> public static void main(String args[]) < Outer.Nested_Demo nested = new Outer.Nested_Demo(); nested.my_method(); >>
Получим следующий результат:
Это мой вложенный класс
Источник: 4java.ru