Вложенные и внутренние классы в Java: типы, примеры и лучшие практики
Вложенные и внутренние классы в Java
Узнайте, как вложенные классы в Java улучшают инкапсуляцию, повышают читаемость и позволяют мощные паттерны внутренних классов.
В Java вы можете объявить класс внутри другого класса — это называется вложенным классом. Например:
class OuterClass { // ... class NestedClass { // ... } }
Существует два основных вида вложенных классов:
- Нестатический вложенный класс (обычно известный как внутренний класс)
- Статический вложенный класс
Рекомендуемое чтение:
- Модификаторы доступа в Java
- Ключевое слово static в Java
Нестатический вложенный класс (Внутренний класс)
Внутренний класс находится внутри внешнего класса и может свободно обращаться к членам внешнего класса, даже к private. Поскольку он привязан к экземпляру внешнего класса, вы должны сначала инстанцировать внешний класс.
Пример 1: Внутренний класс
class CPU { double price; // внутренний класс class Processor{ double cores; String manufacturer; double getCache(){ return 4.3; } } // protected внутренний класс protected class RAM{ double memory; String manufacturer; double getClockSpeed(){ return 5.5; } } } public class Main { public static void main(String[] args) { CPU cpu = new CPU(); CPU.Processor processor = cpu.new Processor(); CPU.RAM ram = cpu.new RAM(); System.out.println("Processor Cache = " + processor.getCache()); System.out.println("Ram Clock speed = " + ram.getClockSpeed()); } }
Вывод:
Processor Cache = 4.3 Ram Clock speed = 5.5
Здесь Processor и RAM вложены внутри CPU. Класс RAM объявлен protected, демонстрируя, что внутренние классы могут использовать любой модификатор доступа Java.
В Main мы сначала инстанцируем внешний класс CPU, затем создаем экземпляры внутреннего класса через экземпляр внешнего:
CPU.Processor processor = cpu.new Processor; CPU.RAM ram = cpu.new RAM();
.) используется для привязки экземпляра внутреннего класса к его внешнему экземпляру.Доступ к членам внешнего класса из внутреннего класса
Внутренние классы могут ссылаться на члены внешнего класса через ключевое слово this с префиксом имени внешнего класса, например, Car.this.carType. Этот синтаксис необходим, когда у внутреннего класса свой контекст this.
Пример 2: Взаимодействие с внешним классом
class Car { String carName; String carType; public Car(String name, String type) { this.carName = name; this.carType = type; } private String getCarName() { return this.carName; } // внутренний класс class Engine { String engineType; void setEngine() { if(Car.this.carType.equals("4WD")){ if(Car.this.getCarName().equals("Crysler")) { this.engineType = "Smaller"; } else { this.engineType = "Bigger"; } } else { this.engineType = "Bigger"; } } String getEngineType(){ return this.engineType; } } } public class Main { public static void main(String[] args) { Car car1 = new Car("Mazda", "8WD"); Car.Engine engine = car1.new Engine(); engine.setEngine(); System.out.println("Engine Type for 8WD= " + engine.getEngineType()); Car car2 = new Car("Crysler", "4WD"); Car.Engine c2engine = car2.new Engine(); c2engine.setEngine(); System.out.println("Engine Type for 4WD = " + c2engine.getEngineType()); } }
Вывод:
Engine Type for 8WD= Bigger Engine Type for 4WD = Smaller
Хотя getCarName() является private, внутренний класс может вызвать его, потому что он находится внутри того же внешнего класса.
Статический вложенный класс
Статический вложенный класс не требует экземпляра внешнего класса для создания. Следовательно, он не может напрямую обращаться к нестатическим членам внешнего класса. Он создается с использованием имени внешнего класса:
OuterClass.NestedClass obj = new OuterClass.NestedClass();
Пример 3: Статический вложенный класс
class MotherBoard { static class USB{ int usb2 = 2; int usb3 = 1; int getTotalPorts(){ return usb2 + usb3; } } } public class Main { public static void main(String[] args) { MotherBoard.USB usb = new MotherBoard.USB(); System.out.println("Total Ports = " + usb.getTotalPorts()); } }
Вывод:
Total Ports = 3
Пример 4: Попытка доступа к членам внешнего класса в статическом вложенном классе
class MotherBoard { String model; public MotherBoard(String model) { this.model = model; } static class USB{ int usb2 = 2; int usb3 = 1; int getTotalPorts(){ if(MotherBoard.this.model.equals("MSI")) { return 4; } else { return usb2 + usb3; } } } } public class Main { public static void main(String[] args) { MotherBoard.USB usb = new MotherBoard.USB(); System.out.println("Total Ports = " + usb.getTotalPorts()); } }
Запуск этого кода производит:
error: non-static variable this cannot be referenced from a static context
Эта ошибка возникает, потому что статический вложенный класс не может ссылаться на MotherBoard.this без экземпляра внешнего класса.
Ключевые выводы
- Внутренние классы рассматриваются как обычные члены внешнего класса и могут быть объявлены
private,protectedилиpublic. - Они могут свободно обращаться ко всем членам внешнего класса, даже к тем, помеченным
private. - Статические вложенные классы не требуют экземпляра внешнего класса и не могут напрямую обращаться к нестатическим членам внешнего класса.
- Использование вложенных классов способствует инкапсуляции и сохраняет связанную логику вместе.
- Внутренние классы идеальны для колбэков, слушателей (listeners) или вспомогательных объектов, тесно связанных с внешним классом.
java
- Вложенные классы в C#: определение, использование и наследование
- Переменные и литералы в Java: подробное руководство
- Классы и объекты в Java: практическое руководство
- Ключевое слово final в Java: переменные, методы и классы
- Оператор instanceof в Java: полное руководство с примерами
- Абстрактные классы и методы в Java: полное руководство
- Статические вложенные классы в Java: использование, отличия и примеры
- Анонимные внутренние классы в Java: определение, синтаксис и практические примеры
- Паттерн Singleton в Java: как реализовать и безопасно использовать
- Рефлексия в Java: инспекция классов, методов и полей во время выполнения