Абстрактные классы и методы в Java

🔥 🚀 Важно для всех, кто работает с Java! 🔥
На JavaRocks ты найдешь уникальные туториалы, практические задачи и редкие книги, которых не найти в свободном доступе. Присоединяйся к нашему Telegram-каналу JavaRocks — стань частью профессионального сообщества!

В этой статье разберемся с абстракциями в Java. Вы можете выбрать удобный для вас формат — посмотреть видеоурок на английском языке, либо же прочитать подробный текстовый разбор ниже.

Если вы только начинаете разбираться в Java, то, скорее всего, уже встречали такое понятие, как “абстракция”. Звучит сложно, но не стоит переживать — всё куда проще, чем кажется. Абстракция — это просто способ упростить вещи, не вникая в реализацию. Например, управляя рулем автомобиля, вы же не думаете каждый раз, как работает двигатель. Разберемся с абстракцией — и всё встанет на свои места.

Что такое абстракция в Java?

Допустим, вы пользуетесь пультом от телевизора. Вы нажимаете кнопку, и он работает. Вас интересуют провода и схемы внутри? Нет! Это и есть абстракция — все мелкие детали скрыты, взаимодействие осуществляется только с нужным интерфейсом.
В Java тот же принцип: показано что делает объект, но скрыто как он это делает. Это делает код чище и упрощает его поддержку.

Абстрактные методы — мощный инструмент в Java, который расширяет возможности ООП, особенно в плане полиморфизма. С их помощью можно задать основу логики, оставив детали реализации подклассам.

Что такое абстрактный метод?

Абстрактный метод — это метод без реализации. У него есть только объявление: имя, тип возвращаемого значения и список параметров. Пример:

public abstract int example(int a1, int a2);

Из этой записи понятно, что метод возвращает значение типа int и принимает два параметра того же типа. А вот как реализован этот метод, сказать нельзя. Чтобы метод заработал, его нужно переопределить.
Создавая абстрактный метод в Java, необходимо соблюдать определенные правила, иначе программа не скомпилируется.
Обратите внимание:

  • Абстрактные методы Java не имеют реализации. Он не должен содержать тело метода (то есть фигурные скобки и код внутри). Объявление просто заканчивается точкой с запятой.
  • Абстрактные методы могут находиться только в абстрактных классах. Объявлять абстрактные методы в конкретных классах запрещено.
    Важно: абстрактный класс может содержать конструкторы и при этом не обязан иметь абстрактные методы.
  • Если конкретный класс наследуется от абстрактного, он обязан реализовать все его абстрактные методы. В противном случае его тоже придётся объявить как abstract.

Последние два пункта могут звучать запутанно, поэтому давайте остановимся на них подробнее.

Наследование абстрактных классов в Java

Допустим, мы хотим написать программу, которая будет рассчитывать периметр и площадь геометрических фигур. Для начала создадим абстрактный родительский класс. Так как для каждой фигуры своя формула, вычисления будут разными. Поэтому пишем абстрактный класс Shape следующим образом:

abstract class Shape {
  		String shapeName = " ";
  		Shape(String name) {
    			this.shapeName = name;
  		}

abstract double area();
  		abstract double perimeter();
}
Run Code

Теперь, чтобы использовать абстрактные методы, нужно унаследовать абстрактный класс Shape и реализовать недостающие методы. То есть каждый конкретный подкласс обязан прописать свою реализацию area() и perimeter(). Например:

class Quadrilateral extends Shape
{
    double length, width;

    Quadrilateral(double l, double w, String name)
    {
        super(name);
        this.length = l;
        this.width = w;
    }

    @Override
    public double perimeter()
    {
        return ((2*length)+(2*width));
    }

    @Override
    public double area()
    {
        return (length*width);
    }
}
Run Code

А вот как использовать этот класс в main:

class Main
{
    public static void main (String[] args)
    {

        // creating a Quadrilateral object using Shape as reference
        Shape rectangle = new Quadrilateral(3,4, "Rectangle");
        System.out.println("Area of rectangle is " + rectangle.area());
        System.out.println("Perimeter of rectangle is " + rectangle.perimeter());

    }
}
Run Code

Вывод в консоли будет выглядеть следующим образом:

Area of rectangle is 12.0
Perimeter of rectangle is 14.0

Важно: Quadrilateral не обязан реализовывать конструктор Shape(String name), потому что это не абстрактный метод — просто обычный конструктор.
А вот если бы было реализовано только area() или только perimeter(), то класс Quadrilateral пришлось бы тоже объявить как abstract, иначе компилятор не пропустит.

Кстати, абстрактные методы можно использовать не только в абстрактных классах, но и в интерфейсах.

Абстрактные методы в интерфейсах Java

Вспомним, что такое интерфейс и чем он отличается от абстрактного класса.

В интерфейсе все переменные по умолчанию являются public static final. А вот в абстрактных классах переменные могут быть любыми, но не final. Методы интерфейса по умолчанию public, а в абстрактных классах можно использовать различные модификаторы доступа. И главное: класс не наследует интерфейс, а реализует его с помощью implements.

До выхода Java 8 интерфейсы могли содержать только абстрактные методы. Теперь интерфейс может иметь стандартные default и статические static методы. И сейчас чаще используют интерфейсы как шаблоны для наследования, а не абстрактные классы.

Если бы мы создали Shape интерфейсом, а Quadrilateral — классом, который его реализует, то пришлось бы отказаться от конструктора Shape(String name), потому что в интерфейсах нет конструкторов. Интерфейс выглядел бы вот так:

interface Shape {

  abstract double area();
  abstract double perimeter();
}
Run Code

А класс Quadrilateral, реализующий этот интерфейс, будет выглядеть так:

class Quadrilateral implements Shape {

  double length, width;

    	  Quadrilateral(double l, double w) {

    	    this.length = l;
    	    this.width = w;
    	  }

    	  @Override
    	  public double perimeter() {

    	    return ((2*length)+(2*width));
    	  }

    	  @Override
    	  public double area() {

   	    return (length*width);
    	  }
}
Run Code

Использование класса — практически такое же:

class Main
{
    public static void main (String[] args)
    {

        // creating a Quadrilateral object using Shape as reference
        Shape rectangle = new Quadrilateral(3,4);
        System.out.println("Area of rectangle is " + rectangle.area());
        System.out.println("Perimeter of rectangle is " + rectangle.perimeter());

    }
}
Run Code

И получим такой вывод в консоли:

Area of rectangle is 12.0
Perimeter of rectangle is 14.0

Зачем использовать абстрактные методы в Java?

Существует множество причин, по которым абстрактные методы в Java используются и почему важно научиться с ними работать. Вот три основные причины, по которым стоит их использовать, когда это уместно:

  1. Предотвращение дублирования. Вспомните пример с геометрическими фигурами. А теперь представьте, что вам и вашей команде нужно создать еще классы для других фигур. Сколько вариантов реализации можно придумать? Десять? Пятнадцать? И это еще простая задача. Представьте себе что-то гораздо более сложное — вариантов решения может быть сотни. Это затруднит объединение всего кода в одну систему. Абстрактные методы помогают задать единый шаблон и избежать разрозненности.
  2. Определенность в реализации. Используя абстрактные методы в интерфейсах и абстрактных классах, вы определяете, как другие разработчики будут взаимодействовать с вашим кодом. Вы задаете названия и сигнатуры методов, указываете, какие данные ожидаются на входе и что будет возвращено. Даже если реализация будет отличаться, интерфейс останется единым. Если кто-то захочет реализовать Shape, то ему придется прописать area() и perimeter().
  3. Читаемость и отладка. Абстрактные методы делают код более читаемым: сразу видно, что класс должен реализовать, что искать, где что править. Это делает процесс чтения кода и устранения ошибок проще. Работа с абстрактными методами — это фундамент для освоения полиморфизма в Java и других объектно-ориентированных языках. Как только вы начнете понимать и использовать эти методы, вы перейдете на новый уровень в программировании.

Какой в этом смысл?

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

Перевод статьи «Java Abstract Class (Abstraction in Java)».

Оставьте комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *

Прокрутить вверх