Абстрактные классы
Бывают классы, объекты которых сами по себе не имеют смысла. «Фигура вообще» не может посчитать свою площадь — это умеют только круг или квадрат. Для таких общих понятий служат абстрактные классы.
Абстрактный метод
Метод с модификатором 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.