Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Оглавление

Абстрактные классы

Бывают классы, объекты которых сами по себе не имеют смысла. «Фигура вообще» не может посчитать свою площадь — это умеют только круг или квадрат. Для таких общих понятий служат абстрактные классы.

Абстрактный метод

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

abstract class Shape {
    abstract double area();
}
 
class Square extends Shape {
    double side;
 
    Square(double side) {
        this.side = side;
    }
 
    @Override
    double area() {
        return side * side;
    }
}
 
void main() {
    Shape shape = new Square(4);
    IO.println(shape.area());
}

Результат:

16.0

Общий код в абстрактном классе

Абстрактный класс может содержать и обычные методы. Они пользуются абстрактными, а реализацию подставляет подкласс:

abstract class Shape {
    abstract double area();
 
    String describe() {
        return "Фигура площадью " + area();
    }
}
 
class Rectangle extends Shape {
    double width;
    double height;
 
    Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
 
    @Override
    double area() {
        return width * height;
    }
}
 
void main() {
    IO.println(new Rectangle(2, 3).describe());
}

Результат:

Фигура площадью 6.0

Метод describe() написан один раз, но работает для любой будущей фигуры.

Поля и конструктор

У абстрактного класса могут быть поля и конструктор. Объект напрямую создать нельзя, но конструктор вызывается из подкласса через super(...):

abstract class Employee {
    protected String name;
 
    Employee(String name) {
        this.name = name;
    }
 
    abstract double salary();
 
    String info() {
        return name + ": " + salary() + " €";
    }
}
 
class Developer extends Employee {
    Developer(String name) {
        super(name);
    }
 
    @Override
    double salary() {
        return 4000;
    }
}
 
class Intern extends Employee {
    Intern(String name) {
        super(name);
    }
 
    @Override
    double salary() {
        return 1200;
    }
}
 
void main() {
    Employee[] team = { new Developer("Анна"), new Intern("Олег") };
    for (Employee e : team) {
        IO.println(e.info());
    }
}

Результат:

Анна: 4000.0 €
Олег: 1200.0 €

Подкласс обязан реализовать всё

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

abstract class Shape {
    abstract double area();
}
 
class Circle extends Shape {
}
 
void main() {
}

Результат:

Main.java:5: error: Main.Circle is not abstract and does not override abstract method area() in Main.Shape
class Circle extends Shape {
^

Когда выбирать абстрактный класс

Абстрактный класс подходит, когда у родственных классов есть общие поля и общий код, а отличаются лишь отдельные шаги. Если общего кода нет и нужно только описать набор методов, лучше подойдёт интерфейс — о нём следующий урок.

Частая ошибка

Объект абстрактного класса создать нельзя — у него есть методы без реализации:

abstract class Shape {
    abstract double area();
}
 
void main() {
    Shape shape = new Shape();
}

Результат:

Main.java:6: error: Main.Shape is abstract; cannot be instantiated
    Shape shape = new Shape();
                  ^

Создавайте объект конкретного подкласса, а переменную можно оставить типа Shape.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.