Конструктор. Финальные поля

Конструктор — это метод, в котором можно привести объект в его начальное состояние. У него нет возвращаемого значения, а имя совпадает с именем класса.

Телефон

Если в классе явно не определён ни один конструктор, генерируется публичный конструктор, который не принимает аргументов. Изменим это: пусть каждый мобильный телефон создаётся с серийным номером и IMEI.

package online.javanese.basics.oop.init;

public abstract class MobilePhone extends Phone {

    private String serialNumber;
    private String imei;

    private int batteryVoltage;

    public MobilePhone(String serialNumber, String imei) {
        this.serialNumber = serialNumber;
        this.imei = imei;
        this.batteryVoltage = 3900;
    }
    
    ...

Конструктор принимает два аргумента — серийный номер и IMEI — и сохраняет их в поля объекта. Также он заряжает батарею до 3,9 вольт. Эквивалентная запись:

package online.javanese.basics.oop.init;

public abstract class MobilePhone extends Phone {

    private String serialNumber;
    private String imei;

    private int batteryVoltage = 3900;

    public MobilePhone(String serialNumber, String imei) {
        this.serialNumber = serialNumber;
        this.imei = imei;
    }

Ключевое слово this указывает на текущий объект. Здесь явно указано this.serialNumber, потому что есть одноимённая локальная переменная.

Теперь возьмёмся за Nexus5:

package online.javanese.basics.oop.init;

public class Nexus5 extends MobilePhone {

    public Nexus5(String serialNumber, String imei) {
        super("NEX-" + serialNumber, imei);
    }

    @Override
    public void dial(String number) {
        System.out.println("Звоним на " + number);
    }
}

Первой строкой в конструкторе должен быть super() — вызов к конструктору суперкласса (придумать, как описать, нафига это). В этом примере любой Nexus5 будет иметь приставку "NEX-" к серийному номеру.

    public static void main(String[] args) {
        Phone nexus = new Nexus5("ASDFG-ZZZZZ", "100500");
        System.out.println(nexus);
        // Nexus5(serialNumber=NEX-ASDFG-ZZZZZ, IMEI=100500, batteryVoltage=3900mV)
    }

Создадим новый конструктор, который посредством магии генерирует серийный номер и IMEI:

import java.util.Random;
import java.util.UUID;

public class Nexus5 extends MobilePhone {

    public Nexus5() {
        this(UUID.randomUUID().toString(),
                Long.toString(new Random().nextLong()));
    }

Ключевое слово this в данном случае — другой конструктор этого класса. Тот, у коготого аргументы String serialNumber, String imei. Тестируем:

        Phone nexus = new Nexus5();
        System.out.println(nexus);
        // например: Nexus5(serialNumber=NEX-62f28c4f-1aaa-4158-81fa-efd77f0c803d, 
        // IMEI=4452673208246011073, batteryVoltage=3900mV)

За всю жизнь телефона его серийный номер и IMEI не могут измениться, поэтому стоит сделать их финальными. А конструктор — это единственное место, где можно задать значения финальных полей.

Вот обновлённый код класса MobilePhone:

package online.javanese.basics.oop.init;

public abstract class MobilePhone extends Phone {

    private final String serialNumber;
    private final String imei;

    private int batteryVoltage = 3900;

    public MobilePhone(String serialNumber, String imei) {
        this.serialNumber = serialNumber;
        this.imei = imei;
        // только в конструкторе и навсегда
    }

    public final String getDisplayVoltage() {
        return batteryVoltage + " мВ";
    }

    @Override
    public String toString() {
        return getClass().getSimpleName() +
                "(serialNumber=" + serialNumber +
                ", IMEI=" + imei +
                ", batteryVoltage=" + batteryVoltage + "mV)";
    }

}

Весь код Nexus5:

package online.javanese.basics.oop.init;

import java.util.Random;
import java.util.UUID;

public class Nexus5 extends MobilePhone {

    public Nexus5() {
        this(UUID.randomUUID().toString(), Long.toString(new Random().nextLong()));
    }//       ↘                             ↘
     //         → → → → ↘                     ↘
    public Nexus5(String serialNumber, String imei) {
        super("NEX-" + serialNumber, imei);
    }

    @Override
    public void dial(String number) {
        System.out.println("Звоним на " + number);
    }

}

Прямоугольник

Во-первых, стоит научиться создавать прямоугольник, находящийся в определённом месте. Во-вторых, нам понадобится копировать прямоугольники. Также стоит оставить возможность пользоваться конструктором без аргументов.

    // создать прямоугольник размера 0х0
    // в точке (0; 0)
    public Rectangle() {
    }

    // создать прямоугольник
    // по заданным параметрам
    public Rectangle(double x1, double y1, double x2, double y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    // создать копию прямоугольника
    public Rectangle(Rectangle other) {
        x1 = other.x1;
        y1 = other.y1;
        x2 = other.x2;
        y2 = other.y2;
    }

Теперь прямоугольники можно копировать, когда это потребуется:

    public static void main(String[] args) {
        // метод для тестирования прямоугольника
        Rectangle rect = new Rectangle();
        rect.setLeftTop(1, 1);
        rect.setRightBottom(2, 2);

        Rectangle copy = new Rectangle(rect);
        // указывает на копию — другой объект

        rect.move(1, 1);
        System.out.println(rect);
        System.out.println(copy);
    }
Rectangle(2.0; 2.0 — 3.0; 3.0)
Rectangle(1.0; 1.0 — 2.0; 2.0)

Весь обновлённый класс Rectangle:

package online.javanese.basics.oop.init;

public final class Rectangle {

    // левый верхний угол
    private double x1;
    private double y1;

    // правый нижний угол
    private double x2;
    private double y2;

    // создать прямоугольник нулевого размера
    // в начале координат
    public Rectangle() {
    }

    // создать прямоугольник
    // в определённом месте
    public Rectangle(double x1, double y1, double x2, double y2) {
        this.x1 = x1;
        this.y1 = y1;
        this.x2 = x2;
        this.y2 = y2;
    }

    // создать копию прямоугольника
    public Rectangle(Rectangle other) {
        x1 = other.x1;
        y1 = other.y1;
        x2 = other.x2;
        y2 = other.y2;
    }

    public void setLeftTop(double x, double y) {
        x1 = x;
        y1 = y;
    }

    public void setRightBottom(double x, double y) {
        x2 = x;
        y2 = y;
    }

    public void moveLeftTop(double dx, double dy) {
        x1 += dx;
        y1 += dy;
    }

    public void moveRightBottom(double dx, double dy) {
        x2 += dx;
        y2 += dy;
    }

    public void move(double dx, double dy) {
        moveLeftTop(dx, dy);
        moveRightBottom(dx, dy);
    }

    @Override
    public String toString() {
        return "Rectangle(" + x1 + "; " + y1 + " — " + x2 + "; " + y2 + ")";
    }

    public static void main(String[] args) {
        // метод для тестирования прямоугольника
        Rectangle rect = new Rectangle();
        rect.setLeftTop(1, 1);
        rect.setRightBottom(2, 2);

        Rectangle copy = new Rectangle(rect);
        // указывает на копию — другой объект

        rect.move(1, 1);
        System.out.println(rect);
        System.out.println(copy);
    }

}
Комментарии к уроку

Сообщить об ошибке