Java inner class и static nested class: полный гайд для новичков

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Вложенные классы в Java: с чего всё началось?

Представьте: вы пишете код на Java, и вдруг понимаете, что один класс логически неразрывно связан с другим. Например, Car и Engine. Двигатель не существует сам по себе — он часть машины. Как это красиво и правильно смоделировать в Java? Ответ — вложенные классы (nested classes).

Тема Java inner class and static nested class — одна из самых частых на Stack Overflow. Тысячи разработчиков путаются: в чём разница? Когда использовать inner, а когда static nested? Почему вообще их придумали?

В этом туториале мы разложим всё по полочкам. Вы не просто узнаете синтаксис — вы поймёте логику Java-дизайнеров. Поехали!

Что такое nested class (вложенный класс)?

Начнём с базы. Nested class — это класс, объявленный внутри другого класса. В Java есть четыре типа вложенных классов, но сегодня нас интересуют два самых популярных:

  • Static nested class (статический вложенный класс)
  • Inner class (внутренний класс, он же non-static nested class)

Ключевое отличие — статический модификатор. Он меняет всё: от доступа к полям до времени жизни объекта. Давайте разбираться на практике.

Static nested class: простой и независимый

Статический вложенный класс ведёт себя как обычный внешний класс, но «живёт» внутри своего родителя. Он не имеет доступа к нестатическим полям и методам внешнего класса (если только не получит ссылку на объект).

Пример из реального мира: Database и DatabaseConfig. Конфигурация не привязана к конкретному экземпляру базы.

public class Database {
    private String url;
    private static String defaultDriver = "com.mysql.cj.jdbc.Driver";

    public Database(String url) {
        this.url = url;
    }

    // Static nested class
    public static class DatabaseConfig {
        private String driver;
        private int poolSize;

        public DatabaseConfig(String driver, int poolSize) {
            this.driver = driver;
            this.poolSize = poolSize;
        }

        public void printConfig() {
            // Имеет доступ только к статическим членам внешнего класса
            System.out.println("Default driver: " + defaultDriver);
            // System.out.println(url); // ОШИБКА! url — нестатическое поле
        }

        public static void staticMethodInNested() {
            System.out.println("Статический метод в статическом вложенном классе");
        }
    }

    public void useConfig() {
        // Создаём экземпляр static nested class
        DatabaseConfig config = new DatabaseConfig("oracle.jdbc.OracleDriver", 10);
        config.printConfig();
    }
}

Обратите внимание: для создания DatabaseConfig нам не нужен объект Database. Это и есть главное преимущество — независимость.

Когда использовать static nested class?

  • Когда вложенный класс логически связан с внешним, но не зависит от его экземпляра.
  • Когда нужно сгруппировать вспомогательные классы (билдеры, конфиги, утилиты).
  • Когда вы проектируете паттерн Builder — классический пример.

Inner class (non-static nested class): связанные навсегда

Внутренний класс — полная противоположность. Он всегда привязан к конкретному объекту внешнего класса. Это значит:

  • Он имеет доступ ко всем полям и методам внешнего класса (даже private).
  • Он не может существовать без экземпляра внешнего класса.
  • Он неявно хранит ссылку на внешний объект (OuterClass.this).

Пример: Car и Engine. У каждой машины свой двигатель, и двигатель «знает» свою машину.

public class Car {
    private String model;
    private int year;

    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }

    // Inner class (non-static)
    public class Engine {
        private int horsepower;
        private String fuelType;

        public Engine(int horsepower, String fuelType) {
            this.horsepower = horsepower;
            this.fuelType = fuelType;
        }

        public void showCarInfo() {
            // Inner class имеет доступ к private полям внешнего класса
            System.out.println("Машина: " + model + " (" + year + ")");
            System.out.println("Двигатель: " + horsepower + " л.с., " + fuelType);
        }

        public void upgradeHorsepower(int extra) {
            this.horsepower += extra;
            // Можно даже изменить внешний объект
            // Car.this.year++; // Например, обновить год
        }
    }

    public void start() {
        // Создаём inner class внутри метода внешнего класса
        Engine engine = new Engine(150, "Бензин");
        engine.showCarInfo();
    }
}

А теперь — как создать inner class снаружи? Это многих путает:

public class Main {
    public static void main(String[] args) {
        // Шаг 1: создаём внешний объект
        Car car = new Car("Toyota Camry", 2022);

        // Шаг 2: создаём внутренний объект через экземпляр внешнего
        Car.Engine engine = car.new Engine(200, "Дизель");
        engine.showCarInfo();

        // Или в одну строку:
        // Car.Engine engine2 = new Car("Honda", 2023).new Engine(180, "Бензин");
    }
}

Обратите внимание на синтаксис: car.new Engine(...). Это не опечатка — так Java показывает, что Engine привязан к конкретному car.

Когда использовать inner class?

  • Когда вложенному классу нужен доступ к данным экземпляра внешнего класса.
  • Когда вы реализуете обработчики событий (например, в GUI).
  • Когда один класс без другого не имеет смысла (например, Order и OrderItem).

Ключевые отличия: таблица сравнения Java inner class vs static nested class

Давайте сведём всё в наглядную таблицу. Это поможет быстро вспомнить разницу на собеседовании или в работе.

Характеристика Static nested class Inner class (non-static)
Доступ к нестатическим членам внешнего класса ❌ Нет (только через ссылку) ✅ Да (напрямую)
Доступ к статическим членам внешнего класса ✅ Да ✅ Да
Требуется экземпляр внешнего класса для создания ❌ Нет ✅ Да

Блоги

Рекомендаций по книгам