Вложенные классы в Java объявляются в теле другого класса. Вложенный класс может иметь модификатор доступа private, public, protected, тогда как внешний класс может иметь только public или default .
Вложенные классы делятся на два типа:
Статический вложенный класс
Статические вложенные классы могут обращаться только к статическим членам внешнего класса. Статический вложенный класс такой же, как и любой другой класс верхнего уровня и является вложенным только для удобства упаковки.
Статические объекты класса могут быть созданы с следующим образом:
1 2 |
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass(); |
Внутренний класс Java
Любой не-статический вложенный класс известен как внутренний класс. Внутренние классы связаны с объектом класса, и они могут получать доступ ко всем переменным и методам внешнего класса. Объект внутреннего класса являются частью объекта внешнего класса. Чтобы создать экземпляр внутреннего класса, мы должны сначала создать экземпляр внешнего класса.
Внутренние классы могут быть созданы так:
1 2 |
OuterClass outerObject = new OuterClass(); OuterClass.InnerClass innerObject = outerObject.new InnerClass(); |
Есть два специальных вида внутренних классов Java.
Локальные внутренние классы
Если класс определяется в теле метода, то его называют локальным внутренним классом. В таких классах допускаются только модификаторы abstract или final. Локальный внутренний класс может получить доступ ко всем членам внешнего класса и локальных final-переменных.
Локальный внутренний класс может быть определен так:
1 2 3 4 5 6 7 8 |
public void print() { //локальный внутренний класс внутри метода class Logger { String name; } //пример использования локального внутреннего класса внутри метода Logger logger = new Logger(); } |
Внутренний анонимный класс
Локальный внутренний класс без имени известен как анонимный внутренний класс. Анонимный класс определяется и конкретизируется в одном заявлении. Анонимный внутренний класс всегда расширяет класс или реализовывает интерфейс. Так как анонимный класс не имеет имени, то не возможно определить конструктор для анонимного класса. Анонимные внутренние классы доступны только в точке, где она определена.
Это немного трудно понимать на слух, поэтому давайте посмотрим на примере.
Вот Java класс с внутренним классом, статическим вложенным классом, локальным внутренним классом и анонимным внутренним классом.
OuterClass.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
package ua.com.prologistic.nested; import java.io.File; import java.io.FilenameFilter; public class OuterClass { private static String name = "OuterClass"; private int i; protected int j; int k; public int l; //конструктор внешнего класса OuterClass public OuterClass(int i, int j, int k, int l) { this.i = i; this.j = j; this.k = k; this.l = l; } public int getI() { return this.i; } //статический вложенный класс, который имеет доступ к статическим переменным/методам внешнего OuterClass static class StaticNestedClass { private int a; protected int b; int c; public int d; public int getA() { return this.a; } public String getName() { return name; } } //внутренний класс, не статический, поэтому имеет доступ ко всем переменным и методам внешнего класса class InnerClass { private int w; protected int x; int y; public int z; public int getW() { return this.w; } public void setValues() { this.w = i; this.x = j; this.y = k; this.z = l; } @Override public String toString() { return "w=" + w + ":x=" + x + ":y=" + y + ":z=" + z; } public String getName() { return name; } } //локальный внутренний класс public void print(String initial) { //локальный внутренний класс внутри метода class Logger { String name; public Logger(String name) { this.name = name; } public void log(String str) { System.out.println(this.name + ": " + str); } } Logger logger = new Logger(initial); logger.log(name); logger.log("" + this.i); logger.log("" + this.j); logger.log("" + this.k); logger.log("" + this.l); } //анонимный внутренний класс public String[] getFilesInDir(String dir, final String ext) { File file = new File(dir); //анонимный внутренний класс реализующий интерфейс FilenameFilter String[] filesList = file.list(new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(ext); } }); return filesList; } } |
Вот тестовая программа, показывающая, как создать экземпляр и использовать вложенный класс в Java.
NestedClassTest.java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
java.util.Arrays; //вложенные классы могут быть импортированы для простоты использования import ua.com.prologisitic.nested.OuterClass.InnerClass; import ua.com.prologisitic.nested.OuterClass.StaticNestedClass; public class NestedClassTest { public static void main(String[] args) { OuterClass outer = new OuterClass(1,2,3,4); //пример использования статического вложенного класса StaticNestedClass staticNestedClass = new StaticNestedClass(); StaticNestedClass staticNestedClass1 = new StaticNestedClass(); System.out.println(staticNestedClass.getName()); staticNestedClass.d=10; System.out.println(staticNestedClass.d); System.out.println(staticNestedClass1.d); //внутренний класс - пример использования InnerClass innerClass = outer.new InnerClass(); System.out.println(innerClass.getName()); System.out.println(innerClass); innerClass.setValues(); System.out.println(innerClass); //вызов метода, используя локальный внутренний класс outer.print("Outer"); //вызов метода, используя анонимный внутренний класс System.out.println(Arrays.toString(outer.getFilesInDir("src/ua/com/prologistic/nested", ".java"))); System.out.println(Arrays.toString(outer.getFilesInDir("bin/ua/com/prologistic/nested", ".class"))); } } |
Результат выполнения программы:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
OuterClass 10 0 OuterClass w=0:x=0:y=0:z=0 w=1:x=2:y=3:z=4 Outer: OuterClass Outer: 1 Outer: 2 Outer: 3 Outer: 4 [NestedClassTest.java, OuterClass.java] [NestedClassTest.class, OuterClass$1.class, OuterClass$1Logger.class, OuterClass$InnerClass.class, OuterClass$StaticNestedClass.class, OuterClass.class] |
Обратите внимание: когда OuterClass компилируется, создаются отдельные файлы класса для внутреннего класса, локального внутреннего класса и статического вложенного класса.
Преимущества вложенных классов в Java
- Если класс полезен только для одного класса, то имеет смысл сделать его вложенным. Это помогает упаковке классов.
- Вложенные классы увеличивают инкапсуляцию. Обратите внимание, что внутренние классы могут получить доступ к private членам класса и в то же время мы можем скрыть внутренний класс от «внешнего мира».
- Вложенные маленькие классы в классах верхнего уровня делают код более читаемым и простым в сопровождении.
Следите за обновлениями на prologistic.com.ua