JavaRush /Курсы /JAVA 25 SELF /Статические вложенные классы (static nested)

Статические вложенные классы (static nested)

JAVA 25 SELF
16 уровень , 1 лекция
Открыта

1. Статический вложенный класс

Статический вложенный класс (static nested class) — это класс, объявленный внутри другого класса с модификатором static. По сути, это обычный класс, который просто «живёт» внутри другого класса, но не связан с его объектом.

Если внутренний класс — это как младший брат, который всегда держится за руку старшего (объекта внешнего класса), то статический вложенный — это кузен, который приезжает только на семейные праздники, а всё остальное время живёт своей жизнью.

Ключевые отличия:

  • Не имеет неявной ссылки на объект внешнего класса — никаких OuterClass.this и доступа к нестатическим членам.
  • Может содержать статические члены (в отличие от обычного внутреннего класса).
  • Создаётся без объекта внешнего класса.

Синтаксис объявления

Объявить статический вложенный класс очень просто: используем ключевое слово static внутри внешнего класса.

class Outer {
    static class Nested {
        void print() {
            System.out.println("Hello from Nested!");
        }
    }
}

Вот и всё! Никаких хитрых синтаксических конструкций — просто static class.

Визуализация:

Outer (внешний класс)
│
├── Nested (static nested class)
│      └── print()

2. Создание экземпляра статического вложенного класса

Самое приятное: не нужен объект внешнего класса!

Outer.Nested nested = new Outer.Nested();
nested.print(); // Hello from Nested!

Обратите внимание: мы используем полное имя класса — Outer.Nested. Это как обращаться к вложенному классу через фамилию: «Смит.Сын».

Сравните с внутренним (inner) классом:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // нужен объект outer

А для static nested — объект Outer не нужен вообще!

3. Доступ к членам внешнего класса

Вот здесь кроется главное отличие от внутреннего класса.

  • Статический вложенный класс имеет доступ ТОЛЬКО к статическим членам внешнего класса.
  • К нестатическим полям и методам обращаться нельзя (даже если они public).

Пример:

class Outer {
    private static int staticValue = 10;
    private int instanceValue = 20;

    static class Nested {
        void show() {
            System.out.println("Static value: " + staticValue); // OK
            // System.out.println("Instance value: " + instanceValue); // Ошибка!
        }
    }
}

Если попытаться обратиться к нестатическому полю instanceValue, компилятор тут же устроит вам воспитательную беседу.

Почему так? Потому что static nested class не «знает», с каким объектом Outer его связывать — у него нет ссылки на объект внешнего класса.

4. Когда использовать статические вложенные классы

Когда они уместны?

  • Когда вложенный класс логически связан с внешним, но не требует доступа к объекту внешнего класса.
  • Когда хотите инкапсулировать вспомогательную структуру: например, builder, утилиту, перечисление или даже маленький immutable-объект.
  • Когда нужно сократить «засорение» пакета: класс нужен только внешнему классу, нет смысла выносить его наружу.

Типичные сценарии:

  • Паттерн Builder (особенно для immutable-объектов)
  • Реализация вспомогательных структур: например, внутренние Node-классы в коллекциях
  • Группировка констант или утилит

Простое правило выбора
Задайте себе вопрос: «Нужен ли моему вложенному классу доступ к конкретному объекту внешнего класса?»
НЕТ → используйте static class (статический вложенный)
ДА → используйте обычный class (внутренний)

5. Примеры использования

Пример 1: Builder для класса

Допустим, у нас есть класс Person, и мы хотим реализовать для него паттерн Builder:

public class Person {
    private final String name;
    private final int age;

    // Приватный конструктор
    private Person(Builder builder) {
        this.name = builder.name;
        this.age = builder.age;
    }

    // Статический вложенный класс Builder
    public static class Builder {
        private String name;
        private int age;

        public Builder setName(String name) {
            this.name = name;
            return this;
        }

        public Builder setAge(int age) {
            this.age = age;
            return this;
        }

        public Person build() {
            return new Person(this);
        }
    }

    public void printInfo() {
        System.out.println("Person: " + name + ", " + age);
    }
}

Использование:

Person person = new Person.Builder()
    .setName("Иван")
    .setAge(30)
    .build();

person.printInfo(); // Person: Иван, 30

Почему Builder — статический вложенный класс?
Потому что он не зависит от объекта Person, а лишь помогает его создать. Он логически связан с Person, но не с конкретным экземпляром.

Пример 2: Вспомогательная структура внутри коллекции

Представим класс «коробка с числами», где для хранения элементов используется внутренний статический класс Node:

public class IntBox {
    private Node head;

    // Вложенный static class
    private static class Node {
        int value;
        Node next;

        Node(int value) {
            this.value = value;
        }
    }

    public void add(int value) {
        Node node = new Node(value);
        node.next = head;
        head = node;
    }

    public void printAll() {
        Node current = head;
        while (current != null) {
            System.out.println(current.value);
            current = current.next;
        }
    }
}

Использование:

IntBox box = new IntBox();
box.add(1);
box.add(2);
box.add(3);
box.printAll(); // 3 2 1

Почему Node — static?
Потому что каждый Node не должен знать о всей коробке (IntBox), он просто хранит данные и ссылку на следующий Node.

Пример 3: Утилитный класс внутри основного

public class MathUtils {
    // Статический вложенный класс для работы с комплексными числами
    public static class Complex {
        private final double re;
        private final double im;

        public Complex(double re, double im) {
            this.re = re;
            this.im = im;
        }

        public Complex add(Complex other) {
            return new Complex(this.re + other.re, this.im + other.im);
        }

        @Override
        public String toString() {
            return re + " + " + im + "i";
        }
    }
}

Использование:

MathUtils.Complex a = new MathUtils.Complex(1, 2);
MathUtils.Complex b = new MathUtils.Complex(3, 4);
MathUtils.Complex sum = a.add(b);
System.out.println(sum); // 4.0 + 6.0i

6. Полезные нюансы

Внутренний класс vs статический вложенный класс

Внутренний (inner) класс Статический вложенный (static nested)
Ключевое слово нет
static
Неявная ссылка на внешний объект да нет
Доступ к нестатическим членам внешнего класса да нет
Доступ к статическим членам внешнего класса да да
Может содержать статические члены нет (только константы) да
Синтаксис создания
outer.new Inner()
new Outer.Nested()
Использование Когда нужен доступ к объекту внешнего класса Когда не нужен доступ к объекту внешнего класса

Иллюстрация

flowchart LR
    OuterClass -->|has| InnerClass
    OuterClass -.->|has| StaticNestedClass
    StaticNestedClass -.->|can access| staticMembers
    InnerClass -->|can access| instanceMembers
    InnerClass -->|can access| staticMembers

Особенности и ограничения

  • Static nested class может содержать как обычные, так и статические поля и методы.
  • Может быть объявлен с любым модификатором доступа (public, private, protected, package-private).
  • Может реализовывать интерфейсы и наследовать от других классов.
  • Может быть generic.
  • Обычно используется для инкапсуляции служебных классов, которые не нужны вне внешнего класса.

Пример generic static nested class:

public class Box {
    public static class Holder<T> {
        private T value;
        public Holder(T value) { this.value = value; }
        public T get() { return value; }
    }
}

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

  • Если вложенному классу нужен доступ к нестатическим полям/методам внешнего класса — используйте обычный inner class.
  • Если класс нужен вне внешнего класса — вынесите его в отдельный файл.
  • Если класс слишком большой или сложный — лучше сделать его отдельным.

7. Типичные ошибки и нюансы

Ошибка №1: Путаница между inner и static nested классом.
Многие новички пытаются в static nested class обратиться к нестатическим полям внешнего класса. Но static nested class не имеет ссылки на объект внешнего класса, поэтому это невозможно. Если вам нужен доступ к состоянию конкретного объекта — используйте обычный inner class.

Ошибка №2: Попытка создать static nested class через объект внешнего класса.
Нет необходимости писать outer.new Inner(). Для static nested class всегда используйте new Outer.Nested().

Ошибка №3: Использование static nested class для логики, требующей доступа к экземпляру внешнего класса.
Если логика класса тесно связана с состоянием объекта внешнего класса, static nested class — плохой выбор. Используйте обычный внутренний класс.

Ошибка №4: Слишком сложная вложенность.
Не злоупотребляйте вложенными классами. Если структура становится запутанной, лучше вынести часть классов наружу.

1
Задача
JAVA 25 SELF, 16 уровень, 1 лекция
Недоступна
Инструментарий волшебника: активизация заклинания 🔮
Инструментарий волшебника: активизация заклинания 🔮
1
Задача
JAVA 25 SELF, 16 уровень, 1 лекция
Недоступна
Секретное хранилище: уровень доступа 🛡️
Секретное хранилище: уровень доступа 🛡️
1
Задача
JAVA 25 SELF, 16 уровень, 1 лекция
Недоступна
Учет ценностей: цепочка артефактов 💎
Учет ценностей: цепочка артефактов 💎
1
Задача
JAVA 25 SELF, 16 уровень, 1 лекция
Недоступна
Издательский дом: создание новой книги 📚
Издательский дом: создание новой книги 📚
Комментарии (19)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
8 мая 2026

public class IntBox {
    private Node firstElement; // Раньше head — ПЕРВЫЙ элемент списка

    private static class Node {
        int storedValue;       // Раньше value — ЧИСЛО внутри узла
        Node nextElement;      // Раньше next — ССЫЛКА на следующий узел

        Node(int incomingValue) {  // Раньше value — значение, ПРИХОДЯЩЕЕ СНАРУЖИ
            this.storedValue = incomingValue;
        }
    }

    public void add(int newValue) {           // Раньше value — НОВОЕ число
        Node newNode = new Node(newValue);    // Раньше node — НОВЫЙ узел
        
        newNode.nextElement = firstElement;   // Новый узел указывает на СТАРЫЙ первый
        firstElement = newNode;               // Теперь НОВЫЙ узел — первый
    }

    public void printAll() {
        Node currentElement = firstElement;   // Раньше current — ТЕКУЩИЙ узел при обходе
        while (currentElement != null) {
            System.out.println(currentElement.storedValue);
            currentElement = currentElement.nextElement;
        }
    }
}
Для меня первый пример показался очень запутанным. По этому мне DeepSeak более менее откомментировал + переименовал переменные, берите кому надо.
Boris Vasilenko Уровень 21
14 апреля 2026
На мой взгляд имеется неточность в определении:

3. Доступ к членам внешнего класса
Вот здесь кроется главное отличие от внутреннего класса.

Статический вложенный класс имеет доступ ТОЛЬКО к статическим членам внешнего класса.
К нестатическим полям и методам обращаться нельзя (даже если они public).
При этом в примере с билдером в методе build() во вложенном статическом классе создается объект внешнего класса с использованием приватного конструктора:

        public Person build() {
            return new Person(this);
        }
То есть, все-таки есть доступ к методам внешнего класса..
dxflt Уровень 25
28 марта 2026
Такой же как и вы новичок, ребят, дам самый дельный совет по моему субъективному мнению. Просто забейте на эти задачи и идите дальше, потом всё придёт. Оставьте их тут. 😉
Cherepoq Уровень 26
4 марта 2026

Самое приятное: не нужен объект внешнего класса!

Outer.Nested nested = new Outer.Nested();
nested.print(); // Hello from Nested!
Обратите внимание: мы используем полное имя класса — Outer.Nested. Это как обращаться к вложенному классу через фамилию: «Смит.Сын».

Сравните с внутренним (inner) классом:

Outer outer = new Outer();
Outer.Inner inner = outer.new Inner(); // нужен объект outer
А для static nested — объект Outer не нужен вообще!
У меня от этого блока чуть крыша не поехала. Мы сначала объявляем объекты Outer.nested... а потом сходу Outer outer и чуть ниже обращаемся Outer.Inner - буквально 3 разных объявления и подписано только одно наверху для статика
18 февраля 2026
Ну и лекция... То ли моего склада ума не хватает чтобы понять что там в примерах, то ли это лекция так сделана... Что думаете?
Olga Уровень 46
21 апреля 2026
Вообще ничего не понятно. Такое впечатление, что пропустили огромный блок информации. Это все равно как с изучения таблицы умножения перейти сразу к логарифмам.
Alexey Ryabikov Уровень 44
5 февраля 2026
файнали, впервые за долгое время мне пришлось включить голову, чтобы решить какую-то задачу
Ernur Adilbek Уровень 19
30 января 2026
я что то вообще не понял 3 задачу, и про цепи. Мы создаем сам объект внутри этого объекта и говорим что это ссылка и еще она работает как список? можете пожалуйста поделится какой нибудь ссылкой который объяснить все это, или я что то пропустил в прошлых уроках
Overbyaka Уровень 57
3 февраля 2026
Это базовая задача на реализацию нодов (узлов). Узел содержит какие-то данные (int value) и ссылку на следующий узел (Node next). Нам не важно, что хранит следующий узел, нам важна ее ссылка, чтоб можно было обратиться к ней по цепочке (Все верно, это односвязный список (бывают еще и двусвязные, когда имеем ссылку на предыдущий и следующий узел)). Это просто нужно разобрать, переварить и самому написать без подглядываний (как очень круто, что есть соответствующая задача!) https://habr.com/ru/articles/717572/ Если все так же непонятно, попробуй погуглить сам тему односвязных и двусвязных списков или найти соответствующую книжку по структурам данным
Yury Lyutov Уровень 36
21 января 2026
Вообще не понял смысла static вложенного класса, как будто с помощью модификаторов доступа и геттеров-сеттеров и так все реализуется, кто то может пояснить разницу??
iseverin Уровень 66
25 января 2026
Внутренний связан с объектом класса и не может существовать без него + имеет доступ ко всем полям объекта и объекту самому. Статический вложенный не имеет доступа к объекту и полям (и никаким модификатором это не реализовать) и не требует создания самого объекта. В начале лекции есть отличный пример - статический вложенный Builder. Он нужен ещё ДО создания самого объекта (что не реализуешь внутренним классом никак) для того, чтобы правильно создать и проинициализировать объект самого внешнего класса.
Iskander Уровень 45
27 января 2026
это наверное по аналогии с заводом изготовителем автомобилей, который заказывает узлы для автомобиля у других производителей.....
Grrbrr7 Уровень 44
8 декабря 2025
В этом уроке пока что самые непонятные примеры эва
Riga Уровень 37
9 ноября 2025
Треш, ну и лекция, половина вообще непонятно. ps. Я про примеры. Особенно не понимаю, зачем про Linked рассказывают если это в 95% случаев не используют, если вообще используют.