Может ли абстрактный класс в Java иметь конструктор?

Ответ

Да, абстрактный класс может и часто должен иметь конструкторы. Хотя экземпляр абстрактного класса создать напрямую нельзя (new AbstractClass() — ошибка компиляции), его конструкторы вызываются при создании экземпляров конкретных классов-наследников.

Для чего это нужно? Конструкторы абстрактного класса используются для инициализации общего состояния (полей), которое есть у всех наследников.

Пример:

abstract class Vehicle {
    private final String id; // Общее поле для всех транспортных средств
    private int fuelLevel;

    // Конструктор абстрактного класса
    public Vehicle(String id, int initialFuel) {
        this.id = id;
        this.fuelLevel = initialFuel;
    }

    public abstract void startEngine();

    // Общий метод, использующий инициализированные поля
    public String getInfo() {
        return "Vehicle ID: " + id + ", Fuel: " + fuelLevel + "%";
    }
}

class Car extends Vehicle {
    private int doors;

    // Конструктор наследника ОБЯЗАН вызвать super(...)
    public Car(String id, int initialFuel, int doors) {
        super(id, initialFuel); // Вызов конструктора родительского абстрактного класса
        this.doors = doors;
    }

    @Override
    public void startEngine() {
        System.out.println("Car engine started.");
    }
}

Ключевые правила:

  • Конструктор абстрактного класса не может быть объявлен как abstract или final.
  • Он может иметь любой модификатор доступа (public, protected, package-private).
  • Если в абстрактном классе не объявлен ни один конструктор, компилятор автоматически создаст конструктор по умолчанию (public AbstractClass() {}).

Ответ 18+ 🔞

Да ты посмотри, какая история интересная вырисовывается! Абстрактный класс, блядь, и конструкторы у него... Ну, казалось бы, зачем, если его самого-то и создать нельзя? А вот поди ж ты, оказывается, без них нихуя не работает!

Представь себе, что абстрактный класс — это как чертёж, ёпта, или, там, устав в армии. Сам по себе устав — это не солдат, его в строй не поставишь. Но когда появляется новый салага (то есть наследник), его, сука, ОБЯЗАНЫ по этому уставу обучить и выдать казённые портянки! Вот эти портянки — это и есть общие поля. А конструктор — это тот самый старшина, который эти портянки и выдаёт.

Смотри, как это выглядит в коде, тут всё чётко:

abstract class Vehicle {
    private final String id; // Номерной знак, штука общая
    private int fuelLevel;   // Бензин, тоже всем нужно

    // А вот и наш "старшина"-конструктор! Не абстрактный, а самый что ни на есть реальный.
    public Vehicle(String id, int initialFuel) {
        this.id = id;
        this.fuelLevel = initialFuel;
    }

    public abstract void startEngine(); // А вот это уже абстрактное, пусть наследники сами думают, как заводиться

    // А это общая бумажка-отчёт, которая уже может пользоваться выданными "портянками"
    public String getInfo() {
        return "Vehicle ID: " + id + ", Fuel: " + fuelLevel + "%";
    }
}

И вот появляется конкретный ублюдок-наследник:

class Car extends Vehicle {
    private int doors; // А это уже его личная приблуда

    // Конструктор наследника. И он ПЕРВЫМ ДЕЛОМ, блядь, должен крикнуть "Так точно, старшина!" — то есть вызвать super().
    public Car(String id, int initialFuel, int doors) {
        super(id, initialFuel); // Смотри сюда! Передаём данные для инита общих полей.
        this.doors = doors;     // А потом уже свои дела устраиваем.
    }

    @Override
    public void startEngine() {
        System.out.println("Дрын-дрын-дрын, завелась тачка.");
    }
}

А если в абстрактном классе конструктора не написать? Да хуй с ним, компилятор сам, тихонько так, подсуетит пустышку public Vehicle() {}. Но это только если тебе вообще не нужно ничего инитить на уровне родителя. А так-то обычно нужно, ёпта.

Короче, суть в чём: конструктор в абстрактном классе — это не для себя, любимого. Это, блядь, контракт для всех своих детей. Мол, «хочешь быть моим наследником — сначала проинициализируй то, что я считаю важным, а потом уже делай что хочешь». Без этого вызова super(...) компилятор тебе мозги выест, и будет прав, пидарас шерстяной.

Так что да, может и должен. Иначе как он общее состояние-то настроит? Волшебной палочкой, что ли?