Конструкторы и поля

Базовый Java
≈ 3 мин чтения

Поля хранят состояние объекта

На прошлой странице мы уже создавали классы и объекты. Теперь посмотрим, откуда объект берёт свои данные. Переменные, объявленные внутри класса вне методов, называются полями. Именно в них объект хранит своё состояние.

class Player {
    String name;
    int level;
}

Player first = new Player();
first.name = "Alex";
first.level = 5;

Player second = new Player();
second.name = "Mia";
second.level = 2;

У first и second свои значения полей. Оба объекта созданы по одному классу Player, но их состояние может отличаться.

Начальные значения полей

Если при создании объекта поле не получило значение явно, Java задаёт ему значение по умолчанию. Для числовых типов это 0, для boolean — false, а для ссылочных типов — null.

class Player {
    String name; // null
    int level;   // 0
}
Это правило относится именно к полям. Локальную переменную внутри метода Java не позволит прочитать, пока ей не присвоено значение.

Если у поля есть естественное начальное значение, его можно указать прямо при объявлении:

class Player {
    String name;
    int level = 1;
}

Конструктор задаёт начальное состояние

Чаще объект должен получить важные данные сразу при создании. Для этого у класса есть конструктор — специальный блок кода, который выполняется при вызове new. Имя конструктора совпадает с именем класса, а возвращаемый тип у него не указывается.

class Player {
    String name;
    int level;

    Player(String name, int level) {
        this.name = name;
        this.level = level;
    }
}

Player player = new Player("Alex", 5);

В выражении new Player("Alex", 5) Java создаёт объект и вызывает подходящий конструктор. Параметры name и level получают переданные значения, а затем они записываются в поля нового объекта.

Запись this.name означает поле name текущего объекта. Здесь this помогает отличить поле от параметра с тем же именем. То же самое происходит с this.level.

Конструкторов может быть несколько

Как и методы, конструкторы можно перегружать: один и тот же класс может поддерживать несколько способов создания объекта, если наборы параметров различаются.

class Player {
    String name;
    int level;

    Player(String name) {
        this(name, 1);
    }

    Player(String name, int level) {
        this.name = name;
        this.level = level;
    }
}

Первый конструктор подходит, когда нужно начать с первого уровня. Вызов this(name, 1) передаёт работу другому конструктору этого же класса, поэтому общую инициализацию не приходится дублировать.

Когда Java создаёт конструктор сама

Если в классе вообще не объявлено ни одного конструктора, компилятор добавляет конструктор без параметров. Именно поэтому в первом примере работал вызов new Player().

Но как только ты объявишь хотя бы один собственный конструктор, автоматически добавленного конструктора без параметров уже не будет.

class Player {
    String name;

    Player(String name) {
        this.name = name;
    }
}

Player player = new Player("Alex");
Не путай конструктор с обычным методом. У конструктора нет возвращаемого типа — даже void. Если написать void Player(), это будет обычный метод с именем Player.