← Назад к вопросам

Всегда ли вызывается родительский конструктор?

2.0 Middle🔥 111 комментариев
#Основы Java

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Всегда ли вызывается родительский конструктор?

Это одна из ключевых особенностей наследования в Java. Ответ: ДА, всегда, но есть важные нюансы о том, когда и как.

Основное правило

Если в конструкторе дочернего класса НЕ вызван явно конструктор родителя (super()), Java АВТОМАТИЧЕСКИ вызовет конструктор без параметров (default constructor) родительского класса.

// Родительский класс
public class Animal {
    private String name;
    
    // Конструктор с параметром
    public Animal(String name) {
        this.name = name;
        System.out.println("Animal constructor called with name: " + name);
    }
    
    // Конструктор без параметров
    public Animal() {
        this.name = "Unknown";
        System.out.println("Animal default constructor called");
    }
}

// Дочерний класс
public class Dog extends Animal {
    private String breed;
    
    // Конструктор 1 - явно вызывает super()
    public Dog(String name, String breed) {
        super(name); // ЯВНЫЙ вызов родительского конструктора с параметром
        this.breed = breed;
        System.out.println("Dog constructor called");
    }
    
    // Конструктор 2 - неявный вызов super()
    public Dog() {
        // Java АВТОМАТИЧЕСКИ добавит super() здесь
        this.breed = "Unknown";
        System.out.println("Dog default constructor called");
    }
}

// Использование
Dog dog1 = new Dog("Buddy", "Labrador");
// Вывод:
// Animal constructor called with name: Buddy
// Dog constructor called

Dog dog2 = new Dog();
// Вывод:
// Animal default constructor called
// Dog default constructor called

Ключевые моменты

1. Явный вызов super()

Если в дочернем конструкторе явно указать super(...), то вызовется УКАЗАННЫЙ конструктор родителя:

public class Parent {
    public Parent() {
        System.out.println("Parent default constructor");
    }
    
    public Parent(String param) {
        System.out.println("Parent constructor with: " + param);
    }
}

public class Child extends Parent {
    // Явный вызов super(String)
    public Child(String value) {
        super(value); // Вызовет Parent(String)
        System.out.println("Child constructor");
    }
    
    // Явный вызов super() - конструктора без параметров
    public Child(int value) {
        super(); // Вызовет Parent()
        System.out.println("Child constructor with int");
    }
}

Child child1 = new Child("test");
// Вывод:
// Parent constructor with: test
// Child constructor

Child child2 = new Child(42);
// Вывод:
// Parent default constructor
// Child constructor with int

2. Неявный вызов super()

Если в конструкторе дочернего класса НЕ указан super() явно, Java добавит super() (без параметров) автоматически:

public class Parent {
    public Parent() {
        System.out.println("Parent default constructor");
    }
    
    public Parent(String param) {
        System.out.println("Parent constructor: " + param);
    }
}

public class Child extends Parent {
    public Child() {
        // Java автоматически добавляет super() в начало
        // (как если бы здесь было явно написано super();)
        System.out.println("Child constructor");
    }
}

Child child = new Child();
// Вывод:
// Parent default constructor
// Child constructor

3. Проблема: нет конструктора без параметров

public class Parent {
    // ВНИМАНИЕ: нет конструктора без параметров!
    public Parent(String param) {
        System.out.println("Parent constructor: " + param);
    }
}

public class Child extends Parent {
    public Child() {
        // ОШИБКА! Java попытается вызвать super(),
        // но его нет! Компиляция не пройдёт.
        // Compilation error: Cannot find symbol
    }
    
    // ПРАВИЛЬНО - явно вызовем нужный конструктор
    public Child(String param) {
        super(param); // Явно указываем, какой конструктор вызвать
    }
}

Порядок инициализации при наследовании

public class GrandParent {
    public GrandParent() {
        System.out.println("1. GrandParent constructor");
    }
}

public class Parent extends GrandParent {
    public Parent() {
        System.out.println("2. Parent constructor");
    }
}

public class Child extends Parent {
    public Child() {
        System.out.println("3. Child constructor");
    }
}

Child child = new Child();
// Вывод:
// 1. GrandParent constructor
// 2. Parent constructor
// 3. Child constructor

// Порядок: от корня иерархии вверх по цепочке наследования!

Инициализация полей и конструкторы

public class Parent {
    private String name = "Parent default"; // Инициализируется СНАЧАЛА
    
    public Parent(String name) {
        this.name = name; // Затем переписывается в конструкторе
        System.out.println("Parent: " + this.name);
    }
}

public class Child extends Parent {
    private String type = "Child default";
    
    public Child(String name, String type) {
        super(name); // Вызывает родительский конструктор
        // После super(), уже инициализированы все поля Parent
        this.type = type;
        System.out.println("Child: " + this.type);
    }
}

Child child = new Child("Test", "Custom");
// Вывод:
// Parent: Test
// Child: Custom

Проблемные сценарии

Забывчивый super()

public class Parent {
    private int id;
    
    public Parent(int id) {
        this.id = id;
        System.out.println("Parent initialized with id: " + id);
    }
    
    public int getId() {
        return id;
    }
}

public class Child extends Parent {
    private String name;
    
    // ОШИБКА: забыли super(id)
    public Child(String name) {
        // Java попытается вызвать super(),
        // но Parent не имеет конструктора без параметров!
        // Компиляция не пройдёт
        this.name = name;
    }
    
    // ПРАВИЛЬНО:
    public Child(String name, int id) {
        super(id); // Обязательно!
        this.name = name;
    }
}

Вызов super() не в начале конструктора

public class Child extends Parent {
    public Child(String name) {
        // ОШИБКА: super() должен быть ПЕРВЫМ вызовом!
        String upper = name.toUpperCase(); // Ошибка!
        super(upper);
    }
    
    // ПРАВИЛЬНО:
    public Child(String name) {
        super(name.toUpperCase()); // super() - первый вызов
        // остальная логика после
    }
}

Практический пример: правильное использование

public class DatabaseEntity {
    private Long id;
    private LocalDateTime createdAt;
    
    public DatabaseEntity(Long id) {
        this.id = id;
        this.createdAt = LocalDateTime.now();
        System.out.println("Entity created with id: " + id);
    }
}

public class User extends DatabaseEntity {
    private String username;
    private String email;
    
    public User(Long id, String username, String email) {
        super(id); // Вызываем родительский конструктор ПЕРВЫМ
        this.username = username;
        this.email = email;
        System.out.println("User created: " + username);
    }
}

public class Admin extends User {
    private List<String> permissions;
    
    public Admin(Long id, String username, String email) {
        super(id, username, email); // Вызываем User конструктор
        this.permissions = new ArrayList<>();
        System.out.println("Admin created: " + username);
    }
}

Admin admin = new Admin(1L, "admin", "admin@example.com");
// Вывод:
// Entity created with id: 1
// User created: admin
// Admin created: admin

// Порядок: DatabaseEntity -> User -> Admin

Вывод

ДА, родительский конструктор ВСЕГДА вызывается:

  1. Явный вызов - если вы напишете super(...), будет вызван УКАЗАННЫЙ конструктор
  2. Неявный вызов - если вы не напишете super(), Java автоматически вызовет super() (конструктор без параметров)
  3. Порядок - родительский конструктор выполняется ПЕРЕД кодом дочернего конструктора
  4. Иерархия - в многоуровневом наследовании конструкторы вызываются по цепочке (от корня к листу)

Правило: super() должен быть ПЕРВЫМ оператором в конструкторе дочернего класса (если его нет явно, Java добавит автоматически).