Лекция 07. Вложенные и внутренние классы¶
Классификация¶
Вложенные и внутренние классы¶
Обычные классы в Java относятся к классам верхнего уровня.
Помимо них в программах могут существовать следующие разновидности вложенных и внутренних классов:
- Статические вложенные классы (static nested classes).
- Внутренние классы (inner classes).
- Локальные классы (local classes).
- Анонимные классы (anonumous classes).
Для чего используют вложенные и внутренние классы:
- Логическая группировка сущностей (все нужное - в одном месте)
- Усиление инкапсуляции (‘’богатый внутренний мир’‘)
- Обеспечение доступа к private-членам со стороны некоторых классов (их делают внутренними)
- Улучшение читаемости программы (все необходимое ‘’под рукой’‘)
Статические вложенные классы¶
Вложенные и внутренние классы¶
Статические вложенные классы (СВК) не имеют доступа к нестатическим полям и методам обрамляющего класса. Доступ к нестатическим полям и методам может осуществляться только через ссылку на экземпляр обрамляющего класса.
СВК имеют доступ к любым статическим методам внешнего класса, в том числе и к приватным.
Польза данных классов заключается в основном в логической группировке сущностей, в улучшении инкапсуляции.
В роли СВК могут выступать интерфейсы
Статические вложенные классы¶
Статический вложенный класс (СВК) определяется внутри другого класса:
class A {
static class B { }
static interface C {}
}
Такие классы (B или C) никак не связаны с экземплярами класса A.
СВК имеет доступ ко всем static-членам внешнего класса, включая закрытые.
Внешний класс тоже имеет доступ ко всем static - членам СВК. Вот так можно создавать экземпляры вложенных статических классов:
class OuterClass {
static class StaticNestedClass {
...
}
}
OuterClass.StaticNestedClass instance =
new OuterClass.StaticNestedClass();
Вложенные классы¶
Интересное использование статических вложенных классов -
тестирование приватных статических методов:
public class ClassToTest {
private static void internalMethod() { ... }
public static class Test {
public void testMethod() { ... }
}
}
Внутренние классы¶
Работа с внутренними классами похожа на работу со статическими вложенными классами, но происходит внутри объектов.
class A {
class B {
...
}
public B get() {
return new B();
}
}
A.B b=a.get();
Данный класс (B) не может иметь статических элементов, а также перечислений.
- Класс B известен только внутри класса A
- Класс B имеет доступ к членам класса A, но класс А не имеет доступа к членам, объявленным внутри B
- После компиляции: A.class и A$B.class
Каждый экземпляр внутреннего класса связан с экземпляром внешнего класса.
Нельзя создать экземпляр внутреннего класса, не создав экземпляр внешнего. Внутренние классы часто используются для предоставления услуг внешним классам.
class A {
class B {
private int data;
public B(int data) {
this.data=data;
}
public int get() {
return data;
}
}
public B getB(int data) {
return new B(data);
}
}
public class Program
{
public static void main(String[] args) {
A a=new A();
A.B c=a.new B(100);
A.B b=a.getB(10);
System.out.println(b.get());
System.out.println(c.get());
}
}
Внешний класс часто содержит метод (вроде getB), возвращающий ссылку на объект внутреннего класса.
Локальные классы¶
Вложенные классы¶
Локальные вложенные классы можно создавать прямо в коде методов:
class A {
void method() {
class B {
...
}
B b=new B();
...
}
}
Ограничения:
- они видны только в пределах блока, в котором объявлены;
- они не могут быть объявлены как private, public, protected или static;
- они не могут иметь внутри себя статических объявлений (полей, методов, классов); исключением являются константы (static final);
Локальные классы¶
Внутренний класс в локальном методе не может использовать локальные переменные внешнего метода до тех пор, пока переменная не будет объявлена как final
class Outer {
public void out() {
final int val=100;
class Inner {
public int get() {
return val;
}
}
Inner in=new Inner();
System.out.println(in.get());
}
}
Анонимные классы¶
Анонимный класс (anonymous class) - это локальный класс без имени.
new Thread(new Runnable() {
public void run() {
...
}
}).start();
Использование анонимных классов оправдано в случаях, когда:
- тело класса является очень коротким;
- нужен только один экземпляр класса;
- класс используется в месте его создания или сразу после него;
- имя класса не важно и не облегчает понимание кода.
В отличие от локальных классов, анонимные должны наследовать существующий класс или интерфейс.
Анонимные классы не могут содержать определение статических полей, методов и классов (кроме констант).
interface Employee {
void info();
}
public class Program {
public static void main(String[] args) {
Employee emp=new Employee() {
public void info() {
System.out.println("Yes!");
}
};
emp.info();
}
}