Абстрактные классы и методы в Java
Абстрактный класс — это класс, который нельзя инстанцировать через new. Он служит «полузаготовкой»: содержит общие поля и методы для семейства наследников и описывает контракт — методы, которые обязаны быть реализованы в каждом потомке.
Метод объявляется ключевым словом abstract и не имеет тела:
public abstract void run();
Если у класса есть хотя бы один абстрактный метод, сам класс тоже должен быть объявлен abstract. Подкласс обязан переопределить все абстрактные методы родителя — иначе он тоже становится абстрактным.
Зачем нужны абстрактные классы:
Зафиксировать общую часть логики (поля, готовые методы) в одном месте.
Заставить наследников реализовать конкретные «слоты» поведения.
Дать каркас для полиморфизма: ссылка типа абстрактного класса принимает объекты любых конкретных наследников.
Синтаксис
public abstract class Device {
String name;
void info() {
System.out.println("Устройство: " + name);
}
public abstract void run(); // нет тела — обязателен в наследниках
}
Пример 1. Базовый абстрактный класс
abstract class Device {
String name;
Device(String name) { this.name = name; }
abstract void run();
}
public class Led extends Device {
Led(String name) { super(name); }
@Override
void run() {
System.out.println(name + ": blink");
}
public static void main(String[] args) {
Led led = new Led("LED1");
led.run();
// Device d = new Device("X"); // ошибка компиляции
}
}
Output:
LED1: blink
Пример 2. Несколько наследников
abstract class Device {
abstract void run();
void hello() {
System.out.println("hello!");
}
}
class Led extends Device {
@Override
void run() { System.out.println("led blink"); }
}
class Motor extends Device {
@Override
void run() { System.out.println("motor spin"); }
}
public class App {
public static void main(String[] args) {
Device[] all = { new Led(), new Motor() };
for (Device d : all) {
d.hello();
d.run();
}
}
}
Output:
hello!
led blink
hello!
motor spin
Пример 3. Шаблонный метод (template method)
abstract class Sensor {
void measure() {
System.out.println("Подготовка...");
int v = read();
System.out.println("Сырое значение: " + v);
System.out.println("Готово");
}
abstract int read();
}
public class TempSensor extends Sensor {
@Override
int read() {
return 25;
}
public static void main(String[] args) {
new TempSensor().measure();
}
}
Output:
Подготовка...
Сырое значение: 25
Готово
Пример 4. Несколько абстрактных методов
abstract class Vehicle {
abstract void start();
abstract void stop();
void cycle() {
start();
System.out.println("...работаем...");
stop();
}
}
public class Robot extends Vehicle {
@Override
void start() { System.out.println("робот стартует"); }
@Override
void stop() { System.out.println("робот остановлен"); }
public static void main(String[] args) {
new Robot().cycle();
}
}
Output:
робот стартует
...работаем...
робот остановлен
Пример 5. Поля и конструктор в абстрактном классе
abstract class Device {
String name;
int pin;
Device(String name, int pin) {
this.name = name;
this.pin = pin;
}
abstract void action();
void describe() {
System.out.println(name + " на пине " + pin);
}
}
public class Buzzer extends Device {
Buzzer(int pin) { super("Buzzer", pin); }
@Override
void action() {
System.out.println("BEEP!");
}
public static void main(String[] args) {
Buzzer b = new Buzzer(8);
b.describe();
b.action();
}
}
Output:
Buzzer на пине 8
BEEP!
Пример 6. Промежуточный абстрактный класс
abstract class Device {
abstract void run();
}
abstract class Light extends Device {
int brightness = 100;
// не реализуем run() — Light тоже abstract
void dim() { brightness /= 2; }
}
public class Lamp extends Light {
@Override
void run() {
System.out.println("Lamp brightness=" + brightness);
}
public static void main(String[] args) {
Lamp lamp = new Lamp();
lamp.run();
lamp.dim();
lamp.run();
}
}
Output:
Lamp brightness=100
Lamp brightness=50
Подводные камни
Абстрактный класс может иметь конструктор, поля и обычные методы — но создавать объекты класса напрямую нельзя.
Если подкласс не реализует все абстрактные методы, он сам должен быть объявлен
abstract.abstractнесовместим сfinal(нельзя «запретить наследование» абстрактному классу) и сprivate(приватный метод нельзя переопределить).Если нужен только контракт без общей реализации — обычно предпочтительнее интерфейс.
Не делайте абстрактный класс «помойкой» для всех общих методов — оставляйте в нём только то, что действительно общее для всех наследников.
См. также
Примечание
Лицензия и источники
Концепция описана на основе официального Java Tutorial от Oracle (https://docs.oracle.com/javase/tutorial/), Oracle Free Documentation License. Перевод, примеры и пояснения — © AlashEd Wiki.