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

Выполняется ли сеттер раньше конструктора

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

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

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

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

Порядок выполнения конструктора и сеттеров

Этот вопрос касается фундаментального понимания жизненного цикла объектов в Java. Ответ прямой: сеттер выполняется только ПОСЛЕ конструктора.

Порядок инициализации объекта

В Java существует чёткий порядок инициализации объекта:

  1. Инициализация переменных класса (статические блоки и инициализаторы) — выполняются один раз при загрузке класса
  2. Инициализация переменных экземпляра (инициализаторы экземпляров) — выполняются перед конструктором
  3. Вызов конструктора — создание экземпляра объекта
  4. Вызов сеттеров — устанавливают значения ПОСЛЕ создания объекта

Пример 1: Базовый случай

public class Person {
    private String name;
    private int age;
    
    // Конструктор
    public Person(String name, int age) {
        System.out.println("1. Конструктор начал работу");
        this.name = name;
        this.age = age;
        System.out.println("2. Конструктор закончил работу");
    }
    
    // Сеттер
    public void setName(String name) {
        System.out.println("3. Сеттер вызван");
        this.name = name;
    }
}

public static void main(String[] args) {
    System.out.println("Начало создания объекта");
    Person person = new Person("John", 25);
    System.out.println("Конец создания объекта");
    
    person.setName("Jane");
}

Вывод:

Начало создания объекта
1. Конструктор начал работу
2. Конструктор закончил работу
Конец создания объекта
3. Сеттер вызван

Пример 2: Инициализаторы блоков

Даже инициализаторы экземпляров (instance initializers) выполняются ДО конструктора:

public class Example {
    private String value;
    
    // Инициализатор экземпляра (блок инициализации)
    {
        System.out.println("1. Инициализатор экземпляра");
        value = "initialized";
    }
    
    // Конструктор
    public Example() {
        System.out.println("2. Конструктор");
    }
    
    // Сеттер
    public void setValue(String value) {
        System.out.println("3. Сеттер");
        this.value = value;
    }
}

public static void main(String[] args) {
    Example example = new Example();
    example.setValue("new value");
}

Вывод:

1. Инициализатор экземпляра
2. Конструктор
3. Сеттер

Пример 3: Наследование

При наследовании порядок более сложный:

class Parent {
    public Parent() {
        System.out.println("1. Parent конструктор");
    }
}

class Child extends Parent {
    private String name;
    
    public Child() {
        System.out.println("2. Child конструктор");
    }
    
    public void setName(String name) {
        System.out.println("3. Child сеттер");
        this.name = name;
    }
}

public static void main(String[] args) {
    Child child = new Child();
    child.setName("John");
}

Вывод:

1. Parent конструктор
2. Child конструктор
3. Child сеттер

Пример 4: Вызов super() в конструкторе

class Parent {
    private String parentValue;
    
    public Parent(String value) {
        System.out.println("1. Parent конструктор, value=" + value);
        this.parentValue = value;
    }
}

class Child extends Parent {
    private String childValue;
    
    public Child(String parentVal, String childVal) {
        super(parentVal);  // Вызов родительского конструктора
        System.out.println("2. Child конструктор");
        this.childValue = childVal;
    }
}

Порядок:

  1. super() вызывает Parent конструктор
  2. После Parent конструктора выполняется Child конструктор
  3. Только потом можно вызывать сеттеры

Spring Context и зависимое внедрение

В Spring Framework порядок может быть другой при использовании аннотаций:

@Component
public class UserService {
    private UserRepository repository;
    
    // Конструктор
    public UserService() {
        System.out.println("1. Конструктор UserService");
    }
    
    // Сеттер с @Autowired
    @Autowired
    public void setRepository(UserRepository repository) {
        System.out.println("2. Сеттер setRepository");
        this.repository = repository;
    }
}

Порядок в Spring:

  1. Вызывается конструктор
  2. Spring вызывает сеттеры с @Autowired

Это всё ещё соответствует правилу: конструктор первый, потом сеттеры.

Полный жизненный цикл объекта

public class LifecycleExample {
    static {
        System.out.println("1. Статический инициализатор (один раз при загрузке класса)");
    }
    
    private String value = initializeField(); // Инициализация переменной
    
    private String initializeField() {
        System.out.println("2. Инициализация переменной экземпляра");
        return "initialized";
    }
    
    {
        System.out.println("3. Инициализатор экземпляра (перед конструктором)");
    }
    
    public LifecycleExample() {
        System.out.println("4. Конструктор");
    }
    
    public void setValue(String value) {
        System.out.println("5. Сеттер");
        this.value = value;
    }
}

public static void main(String[] args) {
    new LifecycleExample();
}

Вывод:

1. Статический инициализатор (один раз при загрузке класса)
2. Инициализация переменной экземпляра
3. Инициализатор экземпляра
4. Конструктор

Заключение

Сеттер НИКОГДА не выполняется раньше конструктора. Это аксиома объектно-ориентированного программирования:

  1. Объект должен быть полностью инициализирован ПЕРЕД взаимодействием с ним
  2. Конструктор отвечает за инициализацию объекта
  3. Сеттеры вызываются ТОЛЬКО после того, как объект полностью создан

Попытка вызвать сеттер до вызова конструктора приведёт к ошибке NullPointerException, так как объект не существует.