JavaRush /Курсы /JAVA 25 SELF /Абстрактные классы и методы: синтаксис, примеры

Абстрактные классы и методы: синтаксис, примеры

JAVA 25 SELF
19 уровень , 1 лекция
Открыта

1. Синтаксис абстрактного класса

Давайте разберёмся, что же такое абстрактный класс в Java и зачем он вообще нужен. Представьте, что у вас есть конструктор LEGO: у вас есть набор деталей (например, «колёса», «кубики»), и есть особые детали для конкретных моделей. Абстрактный класс — это как обобщенная инструкция по обращению с детальками без описания складывания конкретной модели: кубики сцепляются пазами, колёса крепятся к осям, детали можно наращивать слоями. Абстрактный класс описывает именно эти общие правила и обязательные шаги, но не расписывает сборку конкретной модели. Конкретные модели — это подклассы: они берут общую инструкцию и добавляют недостающие шаги.

В Java абстрактный класс — это класс, который не может быть создан напрямую (нельзя сделать new AbstractClass()), но от него можно наследоваться и реализовывать его «недописанные» методы.

Абстрактные классы нужны, когда:

  • У группы объектов есть общее поведение или состояние, но часть логики отличается.
  • Вы хотите реализовать часть функциональности «по умолчанию», а часть оставить на реализацию потомкам.
  • Вы хотите запретить создание объектов этого класса напрямую (например, «Животное» само по себе не встречается, а вот «Кот» — вполне).

Как объявить абстрактный класс

Всё просто: перед словом class пишем ключевое слово abstract.

public abstract class Animal {
    // Поля (например, имя животного)
    protected String name;

    // Конструктор
    public Animal(String name) {
        this.name = name;
    }

    // Абстрактный метод — только объявление, без реализации!
    public abstract void makeSound();

    // Обычный (реализованный) метод
    public void sleep() {
        System.out.println(name + " спит: Zzz...");
    }
}

Особенности:

  • Абстрактный класс может содержать как реализованные методы, так и абстрактные.
  • Абстрактный класс может содержать поля, конструкторы и даже static-методы.
  • Нельзя создать объект абстрактного класса напрямую:
  • Animal a = new Animal("Кто-то"); // Ошибка!

Как объявить абстрактный метод

Абстрактный метод — это метод без тела, то есть без фигурных скобок и кода внутри. Он объявляется с ключевым словом abstract и обязательно заканчивается точкой с запятой ;.

public abstract void makeSound();
  • Абстрактные методы можно объявлять только внутри абстрактного класса.
  • Класс, который наследует абстрактный класс, обязан реализовать все абстрактные методы, иначе он тоже становится abstract.

2. Наследование абстрактных классов: как это работает

Давайте посмотрим на конкретный пример. Пусть у нас есть абстрактный класс Animal с абстрактным методом makeSound(). Теперь создадим класс-наследник Dog, который реализует этот метод:

public class Dog extends Animal {
    public Dog(String name) {
        super(name); // Вызов конструктора базового класса
    }

    @Override
    public void makeSound() {
        System.out.println(name + " лает: Гав-Гав!");
    }
}

И ещё один класс-наследник:

public class Cat extends Animal {
    public Cat(String name) {
        super(name);
    }

    @Override
    public void makeSound() {
        System.out.println(name + " мяукает: Мяу!");
    }
}

Теперь мы можем использовать эти классы в программе:

public class Main {
    public static void main(String[] args) {
        Animal dog = new Dog("Шарик");
        Animal cat = new Cat("Мурка");

        dog.makeSound(); // Шарик лает: Гав-Гав!
        cat.makeSound(); // Мурка мяукает: Мяу!

        dog.sleep(); // Шарик спит: Zzz...
        cat.sleep(); // Мурка спит: Zzz...
    }
}

Обратите внимание:
Мы можем объявлять переменные типа Animal, но создавать объекты только конкретных (не абстрактных) потомков.

Схема: как это выглядит


.         Animal (abstract)
            /         \
         Dog         Cat
 (реализует makeSound) (реализует makeSound)

3. Когда использовать абстрактный класс, а когда интерфейс?

Это один из самых популярных вопросов на собеседованиях, и не зря! Давайте разберёмся:

  • Абстрактный класс — когда у объектов есть общее состояние (например, поля), общая логика (методы с реализацией), и вы хотите дать «скелет» поведения с возможностью доработки.
  • Интерфейс — когда вы хотите задать только набор методов (контракт), без реализации и состояния. С Java 8 интерфейсы получили default/static-методы, но всё равно интерфейс — про «что должен уметь объект», а не «как он это делает».

Пример из жизни:
«Птица» — абстрактный класс: у всех птиц есть клюв, крылья, и они могут летать (но по-разному).
«Летающий» — интерфейс: не только птицы умеют летать, но и самолёты, и супергерои! Летают все по-разному, но главное — они это умеют.

4. Практические примеры

Пример 1: Абстрактный класс с частичной реализацией

Допустим, вы делаете игру, где есть разные виды транспорта. Все они могут ехать, но делают это по-разному. Но у всех есть скорость, название и стандартный способ остановки.

public abstract class Transport {
    protected String name;
    protected int speed;

    public Transport(String name, int speed) {
        this.name = name;
        this.speed = speed;
    }

    // Абстрактный метод — реализация в потомках
    public abstract void move();

    // Реализованный метод
    public void stop() {
        System.out.println(name + " остановился.");
    }
}

public class Car extends Transport {
    public Car(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " едет по дороге со скоростью " + speed + " км/ч.");
    }
}

public class Bicycle extends Transport {
    public Bicycle(String name, int speed) {
        super(name, speed);
    }

    @Override
    public void move() {
        System.out.println(name + " крутит педали со скоростью " + speed + " км/ч.");
    }
}

Использование:

Transport car = new Car("Toyota", 120);
Transport bike = new Bicycle("Stels", 25);

car.move(); // Toyota едет по дороге со скоростью 120 км/ч.
bike.move(); // Stels крутит педали со скоростью 25 км/ч.

car.stop(); // Toyota остановился.
bike.stop(); // Stels остановился.

Пример 2: Абстрактный метод с параметром

public abstract class Shape {
    public abstract double area();
}

public class Circle extends Shape {
    private double radius;
    public Circle(double radius) {
        this.radius = radius;
    }
    @Override
    public double area() {
        return Math.PI * radius * radius;
    }
}

public class Rectangle extends Shape {
    private double width, height;
    public Rectangle(double width, double height) {
        this.width = width;
        this.height = height;
    }
    @Override
    public double area() {
        return width * height;
    }
}

Использование:

Shape c = new Circle(3);
Shape r = new Rectangle(4, 5);

System.out.println("Площадь круга: " + c.area());
System.out.println("Площадь прямоугольника: " + r.area());

5. Особенности и нюансы абстрактных классов

  • Абстрактный класс может содержать любые модификаторы доступа: public, protected, private (например, для полей).
  • Можно объявлять абстрактный класс без абстрактных методов. Это бывает полезно, если вы просто хотите запретить создание экземпляров базового класса.
  • Если класс наследует абстрактный класс, но не реализует все абстрактные методы, он тоже должен быть объявлен как abstract.
  • Абстрактный класс может иметь конструкторы. Они вызываются при создании объекта-наследника (через super(...)).
  • Абстрактные методы не могут быть private (иначе их нельзя будет реализовать в наследнике).
  • Абстрактные классы могут содержать static-методы и поля.
  • Абстрактный класс может реализовывать интерфейсы, но не обязан реализовывать их методы — это могут сделать потомки.

Таблица: сравнение абстрактного класса и интерфейса

Абстрактный класс Интерфейс
Ключевое слово
abstract class
interface
Может содержать поля Да (любые) С Java 8 — только static/final
Методы с реализацией Да С Java 8 — default/static
Абстрактные методы Да Да
Множественное наследование Нет Да (можно реализовать много интерфейсов)
Конструкторы Да Нет
Можно создать объект Нет Нет

6. Типичные ошибки при работе с абстрактными классами и методами

Ошибка №1: попытка создать экземпляр абстрактного класса.
Если вы напишете new Animal("Кто-то"), компилятор сразу же напомнит, что абстрактные классы для этого не предназначены. Помните: абстракция — это «скелет», а не «живой организм».

Ошибка №2: забыли реализовать все абстрактные методы в наследнике.
Если ваш класс не реализует хотя бы один абстрактный метод базового класса, он сам должен быть объявлен как abstract, иначе получите ошибку компиляции.

Ошибка №3: объявили абстрактный метод вне абстрактного класса.
В Java нельзя объявить абстрактный метод в обычном (неабстрактном) классе — компилятор тут же возмутится.

Ошибка №4: попытка сделать абстрактный метод private или static.
Абстрактные методы не могут быть private (иначе их нельзя переопределить) и не могут быть static (потому что статические методы не переопределяются). Ну и final тоже не могут, потому что final запрещает переопределение.

Ошибка №5: забыли про модификатор доступа у абстрактного метода.
Если вы явно не укажете модификатор, метод будет иметь пакетную видимость (package-private), что иногда не то, что вы хотели получить.

1
Задача
JAVA 25 SELF, 19 уровень, 1 лекция
Недоступна
Еще один житель цифрового зоопарка 🐾
Еще один житель цифрового зоопарка 🐾
1
Задача
JAVA 25 SELF, 19 уровень, 1 лекция
Недоступна
Система управления "Умным домом" 📱
Система управления "Умным домом" 📱
1
Задача
JAVA 25 SELF, 19 уровень, 1 лекция
Недоступна
Геометрический редактор: фигуры и их площади 📐
Геометрический редактор: фигуры и их площади 📐
1
Задача
JAVA 25 SELF, 19 уровень, 1 лекция
Недоступна
Кадровая система IT-компании 💼
Кадровая система IT-компании 💼
Комментарии (9)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
kasnil Уровень 20
20 января 2026
JAVA 25 SELF:

Заменить вызов IO.println на System.out.println или обеспечить существование 
класса IO с методом println. В текущем коде используется неизвестный класс IO, 
что приведёт к ошибке компиляции, если класса IO нет в проекте.
Kidze Уровень 21
5 января 2026
Муууу! Zzz...
Maks Уровень 31
3 декабря 2025
может еще 10 лекций будем повторять одно и тоже?
Ksanders Уровень 32
29 ноября 2025
В лекции идет повторение синтаксиса написания абстрактного класса, хотя уже это было на уровне про наследование. А потом сразу сравнение между абстрактным классом и интерфейсом, хотя не объясняется абсолютно что это такое интерфейс и с чем его едят вообще 😕
Anonymous #3356042 Уровень 40
21 октября 2025
Задач - проектов действительно не хватает. На тех задачах что даны алгоритмам не научишься
I'll kick them all Уровень 5
25 сентября 2025
А куда делись задачи - проекты? Почему нужно копировать из задачи в задачу код?
Anton Pohodin Уровень 27
8 октября 2025
Последняя задача про кадровую систему содержит неполные требования (касаемо getName()), так что пришлось додумываться самому...
Ksanders Уровень 32
29 ноября 2025
Зато последняя задача хоть немного заставляет задумываться над реализацией (в первые за последние уровни)
Kidze Уровень 21
5 января 2026
Что-то похожее на easy минимальный уровень, да.