Внутренние и вложенные классы java. Часть 2
02.03.2017 — 2019 год
<<< Часть 1
Часть 3 >>>
Часть 2
Внутренние классы
Inner Classes — Внутренние классы
Внутренний класс связан с экземпляром его обрамляющего класса (из документации).
Пример внутреннего класса есть в документации.
Создадим класс:
Так в чем же отличие, спросите вы. Объявления классов и вложенных и внутренних
одинаковые в данных случаях. Отличие в том, что внутренний класс связан с внешним классом через экземпляр, или через объект класса.
Чтобы создать экземпляр внутреннего класса, нам нужно сначала создать экземпляр внешнего класса. Затем создать внутренний объект, в пределах внешнего объекта, таким образом:
Пример:
По-другому мы можем написать так:
Обратите внимание на запись вида
Рассмотрим свойства внутренних классов.
Внутренние классы есть смысл использовать, если они будут использовать элементы родителя,
чтобы не передавать лишнего в конструкторах. Внутренний класс неявно наследуется от внешнего класса, хотя мы не используем ключевое слово extends в случае с классом или implements в случае с интерфейсом. То есть, во внутреннем классе мы можем использовать весь унаследованный функционал внешнего класса. Может показаться, что это сомнительно. Но это дает нам более гибкий подход. Таким образом мы можем использовать во внутреннем классе, функционал унаследованный от внешнего класса.
Внутренний класс стоит использовать, когда нам нужна инкапсуляция. Во внутреннем классе мы, таким образом закрываем всё от «внешнего мира».
Например, Map.Entry — нигде кроме интерфейса Map и его реализаций он не используется. Смотрите исходный код Map.Entry и Map. Это я привел только один пример.
Далее рассмотрим пример явного наследования.
В этом примере у нас, по сути, получилось множественное наследование, и мы можем использовать функционал класса AnyClass и функционал класса Outer6.
Диаграмма наследования:
рис. 1
Здесь модификатор доступа у класса Outer6 по умолчанию. То есть класс Outer6 виден только в нашем пакете (package inner). Класс Inner6 закрыт от внешнего мира и внешнего воздействия.
То есть более «защищен».
Это только пример множественного наследования от «прилегающего» класса и класса «оболочки». На практике вам вряд-ли такое понадобится. Тут я рассматриваю такую возможность только в учебных целях и для лучшего понимания.
Замечание Выражение: «прилегающего» класса — взято из книги «Философия Java».
Дополним пример.
В этом примере видно, что мы можем использовать как поля и методы «окружающего» класса — Outer7, так поля и методы того класса, от которого мы наследовали внутренний класс — AnyClass2. Это дает нам несколько большие возможности и гибкость при использовании внутреннего класса. Хотя для множественного наследования более подходят интерфейсы.
Совет из книги «Философия Java. Брюс Эккель. ISBN 5-272-00250-4» c. 313:
Чтобы использовать внутренний класс, за пределами обычных методов «окружающего» класса необходимо создать объект внутреннего класса следующим способом.
ИмяВнешнегоКласса.ИмяВнутреннегоКласса.
Объект внутреннего класса сохраняет информацию о месте, где он был создан.
Для вашего комфорта, я создал репозиторий на github.
Теперь вы можете скачать актуальные версии кода, для ваших экспериментов, тестов и изучения:
github.com/vvm64/InnerAndNestedCl
Часть 3 >>>
Литература
Майкл Морган. «Java 2.Руководство разработчика» ISBN 5-8459-0046-8
Брюс Эккель. «Философия Java.» ISBN 5-272-00250-4
Герберт Шилдт «Java. Полное руководство. 8-е издание.» ISBN: 978-5-8459-1759-1
Ссылки:
ru.wikipedia.org
src-code.net/lokalnye-vnutrennie-klassy-java
Документация Oracle
02.03.2017 — 2019 год
<<< Часть 1
Часть 3 >>>
Часть 2
Внутренние классы
Inner Classes — Внутренние классы
Внутренний класс связан с экземпляром его обрамляющего класса (из документации).
Пример внутреннего класса есть в документации.
Создадим класс:
/* Пример №7 */
class OuterClass {
...
class InnerClass {
...
}
}
Так в чем же отличие, спросите вы. Объявления классов и вложенных и внутренних
одинаковые в данных случаях. Отличие в том, что внутренний класс связан с внешним классом через экземпляр, или через объект класса.
Чтобы создать экземпляр внутреннего класса, нам нужно сначала создать экземпляр внешнего класса. Затем создать внутренний объект, в пределах внешнего объекта, таким образом:
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
Пример:
/* Пример №8 файл Outer.java*/
package inner;
/**
*
* @author Ar20L80
*/
public class Outer {
class InnerClass {
}
Outer(){}
public static void main(String[] args) {
Outer outerObject = new Outer();
Outer.InnerClass innerObject = outerObject.new InnerClass(); // создание экземпляра
внутреннего класса
}
}
По-другому мы можем написать так:
/*
Учебный пример №9
файл Outer5.java
Внутренние классы
Получить ссылку на внешний класс в конструкторе внутреннего
*/
package inner;
/**
*
* @author Ar20L80
*/
public class Outer5 {
class Inner5{
private Outer5 myOuter;
Inner5(){
myOuter = Outer5.this;
}
}
public static void main(String[] args){
Outer5 outer5 = new Outer5();
}
}
Обратите внимание на запись вида
myOuter = Outer5.this;
. Она означает получение ссылки на текущий экземпляр внешнего класса Outer5.this.Рассмотрим свойства внутренних классов.
Внутренние классы есть смысл использовать, если они будут использовать элементы родителя,
чтобы не передавать лишнего в конструкторах. Внутренний класс неявно наследуется от внешнего класса, хотя мы не используем ключевое слово extends в случае с классом или implements в случае с интерфейсом. То есть, во внутреннем классе мы можем использовать весь унаследованный функционал внешнего класса. Может показаться, что это сомнительно. Но это дает нам более гибкий подход. Таким образом мы можем использовать во внутреннем классе, функционал унаследованный от внешнего класса.
Внутренний класс стоит использовать, когда нам нужна инкапсуляция. Во внутреннем классе мы, таким образом закрываем всё от «внешнего мира».
Например, Map.Entry — нигде кроме интерфейса Map и его реализаций он не используется. Смотрите исходный код Map.Entry и Map. Это я привел только один пример.
Далее рассмотрим пример явного наследования.
/*
Учебный пример №10(1).
файл Outer6.java
Внутренние классы
*/
package inner;
/**
*
* @author Ar20L80
*/
class AnyClass{} // класс от которого наследуем Inner6
public class Outer6 { // внешний класс
class Inner6 extends AnyClass{ // внутренний класс явно унаследован от "прилегающего"
// тут мы унаследовали внутренний класс от AnyClass{}
// и можем расширить функциональность класса AnyClass{}
// и класса Outer6
}
}
В этом примере у нас, по сути, получилось множественное наследование, и мы можем использовать функционал класса AnyClass и функционал класса Outer6.
Диаграмма наследования:
рис. 1
Здесь модификатор доступа у класса Outer6 по умолчанию. То есть класс Outer6 виден только в нашем пакете (package inner). Класс Inner6 закрыт от внешнего мира и внешнего воздействия.
То есть более «защищен».
Это только пример множественного наследования от «прилегающего» класса и класса «оболочки». На практике вам вряд-ли такое понадобится. Тут я рассматриваю такую возможность только в учебных целях и для лучшего понимания.
Замечание Выражение: «прилегающего» класса — взято из книги «Философия Java».
Дополним пример.
/*
Учебный пример №11
файл Outer7.java
Внутренние классы
*/
package inner;
/**
*
* @author Ar20L80
*/
class AnyClass2{
void anyClass2Method(){}
}
public class Outer7 {
private int iOuterVar;
private class Inner7 extends AnyClass2
{
private Outer7 out7;
public Inner7() {
out7 = Outer7.this; // ссылка на окружающий класс
}
private int anyMethodOfInner7(){
super.anyClass2Method();// можем вызвать метод нашего супер класса AnyClass2
return out7.iOuterVar; // можем обратиться к переменным
// и методам Outer7
}
}
}
В этом примере видно, что мы можем использовать как поля и методы «окружающего» класса — Outer7, так поля и методы того класса, от которого мы наследовали внутренний класс — AnyClass2. Это дает нам несколько большие возможности и гибкость при использовании внутреннего класса. Хотя для множественного наследования более подходят интерфейсы.
Совет из книги «Философия Java. Брюс Эккель. ISBN 5-272-00250-4» c. 313:
«Каждый внутренний класс может независимо наследовать определенную реализацию.
Внутренний класс не ограничен при наследовании в ситуациях, где внешний класс уже наследует реализацию.»
Чтобы использовать внутренний класс, за пределами обычных методов «окружающего» класса необходимо создать объект внутреннего класса следующим способом.
ИмяВнешнегоКласса.ИмяВнутреннегоКласса.
Объект внутреннего класса сохраняет информацию о месте, где он был создан.
Для вашего комфорта, я создал репозиторий на github.
Теперь вы можете скачать актуальные версии кода, для ваших экспериментов, тестов и изучения:
github.com/vvm64/InnerAndNestedCl
Часть 3 >>>
Литература
Майкл Морган. «Java 2.Руководство разработчика» ISBN 5-8459-0046-8
Брюс Эккель. «Философия Java.» ISBN 5-272-00250-4
Герберт Шилдт «Java. Полное руководство. 8-е издание.» ISBN: 978-5-8459-1759-1
Ссылки:
ru.wikipedia.org
src-code.net/lokalnye-vnutrennie-klassy-java
Документация Oracle