Абстрактные классы и методы в 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.