Что такое абстрактный класс
Перейти к содержимому

Что такое абстрактный класс

  • автор:

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

Абстрагирование – это процесс, в ходе которого от пользователя скрываются многие детали реализации, а предоставляются только те детали, которые действительно важны. Так удаётся сфокусироваться на том, что делает объект, а не как он это делает.

В Java абстрактные классы и методы – это основные инструменты для реализации абстракций. Абстрактные классы служат шаблонами для создания субклассов, а абстрактные методы можно сравнить с чертежами, описывающими поведение этих субклассов.

Если вы новичок в Java или хотите освежить знания о том, чем отличаются абстрактные классы или интерфейсы, то можете почитать руководство и на эту тему: Difference Between Interface and Abstract class in Java.

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

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

public abstract class Shape < // class body >

Обратите внимание: абстрактные классы могут содержать как абстрактные, так и неабстрактные методы, а также переменные экземпляров, конструкторы и другие члены. Правда, напрямую инстанцировать абстрактные классы нельзя, а это означает, что их не получится напрямую использовать для создания объектов.

Различия между абстрактными и конкретными классами

Для абстрактных классов (в отличие от конкретных) нельзя напрямую создавать экземпляры. Напротив, абстрактные классы непосредственно предназначены для того, чтобы их расширяли другие классы, которые затем могут реализовывать абстрактные методы и наследовать неабстрактные члены и поведение абстрактного класса.

Кроме того, у абстрактных классов могут быть конструкторы, но их нельзя вызывать прямо из субклассов. Напротив, конструктор конкретного субкласса обязан явно вызывать конструктор соответствующего суперкласса. Для этого вызывается либо super() , либо конкретный конструктор суперкласса.

Когда использовать абстрактные классы: пример

Абстрактные классы часто применяются для определения общего интерфейса или такого поведения, которое может совместно использоваться сразу множеством субклассов. Например, представьте, что вы проектируете игру, в которой используются различные фигуры – скажем, круги, квадраты и треугольники. У всех этих фигур есть определённые общие свойства, например, периметр и площадь. Но у них могут быть и уникальные характеристики, такие как количество сторон и радиус.

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

public abstract class Shape < protected int x, y; public Shape(int x, int y) < this.x = x; this.y = y; >public abstract double getArea(); public abstract double getPerimeter(); >

В этом примере класс Shape содержит переменные экземпляра для координат x и y некоторой фигуры, а также абстрактные методы для вычисления площади и периметра. Определяя эти методы как абстрактные, мы позволяем каждому конкретному субклассу реализовать их по-своему.

Например, можно было бы создать субкласс Circle , расширяющий класс Shape и реализующий собственные версии методов getArea() и getPerimeter() :

public class Circle extends Shape < private double radius; public Circle(int x, int y, double radius) < super(x, y); this.radius = radius; >public double getArea() < return Math.PI * radius * radius; >public double getPerimeter() < return 2 * Math.PI * radius; >> 

Аналогично, можно было бы создать субклассы Square и Triangle , также реализующие собственные версии методов getArea() и getPerimeter() , в то же время наследующие координаты x и y от суперкласса Shape .

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

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

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

public abstract double getArea();

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

Правила и ограничения при работе с абстрактными методами

Существует несколько правил и ограничений, применимых к абстрактным методам в Java:

  • Абстрактный метод не может быть объявлен как final или private.
  • Абстрактный метод обязательно должен объявляться внутри абстрактного класса.
  • Конкретный субкласс, расширяющий абстрактный класс, обязательно должен предоставлять реализацию для всех его унаследованных абстрактных методов.

Мы уже определили абстрактный класс Shape , содержащий абстрактные методы для вычисления площади и периметра фигуры:

public abstract class Shape < protected int x, y; public Shape(int x, int y) < this.x = x; this.y = y; >public abstract double getArea(); public abstract double getPerimeter(); >

Чтобы создать конкретный субкласс Shape , необходимо реализовать следующие абстрактные методы:

public class Circle extends Shape < private double radius; public Circle(int x, int y, double radius) < super(x, y); this.radius = radius; >public double getArea() < return Math.PI * radius * radius; >public double getPerimeter() < return 2 * Math.PI * radius; >>

В данном примере класс Circle реализует методы getArea() и getPerimeter() при помощи собственных уникальных формул для расчёта площади круга и периметра окружности.
Аналогично, можно было бы создать субклассы Square и Triangle , реализующие собственные версии методов getArea() и getPerimeter().

Используя абстрактные методы в сочетании с абстрактными классами, можно предоставить общий интерфейс для вычисления площади и периметра различных фигур, в то же время позволяя каждому конкретному субклассу по-своему реализовывать эти методы.

Наилучшие практики

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

  1. Пользуйтесь абстрактными классами, чтобы моделировать иерархии взаимосвязанных классов: при помощи абстрактных классов очень удобно представить группу таких взаимосвязанных классов, которые совместно используют некий общий функционал. Создавая абстрактный класс, который определяет общие методы и свойства, вы тем самым избегаете дублирования, повышаете модульность вашего кода и облегчаете его поддержку.
  2. Пользуйтесь абстрактными методами, чтобы определять общее поведение: абстрактные методы полезны в тех случаях, когда требуется навязать конкретное поведение сразу для множества субклассов. Определяя абстрактный метод в абстрактном классе, вы можете гарантировать, что все субклассы (каждый по-своему) будут реализовывать одно и то же поведение.
  3. Не переборщите с абстрактными классами и методами: притом, что абстрактные классы и методы могут быть довольно мощными, важно не прибегать к ним сверх меры. Вообще, следует создавать абстрактный класс или метод только в том случае, когда на то есть явная причина. Если слишком активно ими пользоваться, то код может излишне усложниться, и его станет тяжелее поддерживать.
  4. Придерживайтесь соглашений об именованиях: подбирая имена для абстрактных классов и методов, важно придерживаться стандартных соглашений об именованиях, действующих в Java. Именем абстрактного класса должно быть абстрактное существительное (напр., “Shape”), а имена абстрактных методов должны быть глаголами (напр. “draw”).
  5. Документируйте ваш код: как и при работе с любым кодом, абстрактные классы и методы важно документировать, чтобы они были понятнее другим разработчикам. Снабжайте код чёткими и краткими комментариями, которые поясняли бы смысл поведения каждого класса и метода, а также их назначение.

Заключение

Итак, абстрактные классы и методы – это мощные инструменты для реализации абстракций в Java. Умело пользуясь ими, вы сможете создавать более модульный и удобный в поддержке код, который проще понимать и расширять. Если вы моделируете иерархии взаимосвязанных классов или определяете общее поведение, которое должно реализовываться сразу во множестве субклассов, то вам в этом могут особенно помочь абстрактные классы и методы. Пользуясь рекомендованными практиками, рассмотренными выше, вы сможете освоить этот важный аспект программирования на Java.

Часто задаваемые вопросы

• Могут ли у абстрактных классов быть конструкторы?

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

• Могут ли абстрактные классы реализовывать интерфейсы?
Да, абстрактные классы могут реализовывать интерфейсы, это могут делать вообще любые классы. Эта возможность может пригодиться, если вы хотите предоставить некое общее поведение сразу для нескольких классов, так, чтобы они реализовывали один и тот же интерфейс.

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

• Могут ли абстрактные классы быть финальными?
Нет, абстрактные классы не могут быть финальными, так как они предназначены именно для расширения субклассами. Если сделать абстрактный класс финальным, то такое расширение будет исключено.

• Когда следует использовать абстрактные классы вместо интерфейсов?
Абстрактные классы хорошо вам подойдут, если вы хотите предоставить некоторый общий функционал для множества классов, входящих в общую иерархию. Интерфейсы лучше подходят для определения такого набора, методы из которого разные классы могут реализовывать независимо. Правило такое: пользуйтесь абстрактными классами, когда хотите предоставить базовую реализацию для группы взаимосвязанных классов. Интерфейсы уместнее, когда нужно определить группу методов для реализации разрозненными классами, в каждом по-своему.

  • Блог компании Издательский дом «Питер»
  • Java
  • Совершенный код
  • ООП

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

Класс, содержащий абстрактные методы, называется абстрактным классом. Такие классы помечаются ключевым словом abstract.

Абстрактный метод не завершён. Он состоит только из объявления и не имеет тела:

abstract void yourMethod();

По сути, мы создаём шаблон метода. Например, можно создать абстрактный метод для вычисления площади фигуры в абстрактном классе Фигура. А все другие производные классы от главного класса могут уже реализовать свой код для готового метода. Ведь площадь у прямоугольника и треугольника вычисляется по разным алгоритмам и универсального метода не существует.

Если вы объявляете класс, производный от абстрактного класса, но хотите иметь возможность создания объектов нового типа, вам придётся предоставить определения для всех абстрактных методов базового класса. Если этого не сделать, производный класс тоже останется абстрактным, и компилятор заставит пометить новый класс ключевым словом abstract.

Можно создавать класс с ключевым словом abstract даже, если в нем не имеется ни одного абстрактного метода. Это бывает полезным в ситуациях, где в классе абстрактные методы просто не нужны, но необходимо запретить создание экземпляров этого класса.

В тоже время абстрактный класс не обязательно должен иметь только абстрактные методы. Напомню ещё раз, что если класс содержит хотя бы один абстрактный метод, то он обязан быть сам абстрактным.

Создавать объект на основе абстрактного класса нельзя.

 // нельзя. даже не пытайтесь AbstractClass abstractClass = new AbstractClass(); 

Абстрактный класс не может содержать какие-либо объекты, а также абстрактные конструкторы и абстрактные статические методы. Любой подкласс абстрактного класса должен либо реализовать все абстрактные методы суперкласса, либо сам быть объявлен абстрактным. Короче, я сам запутался. Пойду лучше кота поглажу.

Я вернулся. Давайте напишем пример для абстрактного класса.

Допустим, мы хотим создать абстрактный класс СферическийКонь и не менее идиотский класс СферическийКоньВВакууме, наследующий от первого класса.

 package ru.alexanderklimov.expresscourse; public abstract class SphericalHorse < // абстрактный метод ржать() abstract void neigh(); // абстрактный класс может содержать и обычный метод void gallop() < System.out.println("Куда прёшь?"); >> class SphericalHorseInVacuum extends SphericalHorse

Когда вы напишете такой код, то студия подчеркнёт второй класс красной волнистой линией и предложит реализовать обязательный метод, который определён в абстрактном классе.

Abstract

Abstract

Соглашаемся и дописываем в созданную заготовку свой код для метода.

 @Override void neigh()

В главной активности напишем код для щелчка кнопки.

 public void onClick(View view) < SphericalHorseInVacuum horse = new SphericalHorseInVacuum(); horse.neigh(); // на основе абстрактного метода horse.gallop(); // обычный метод >

Обратите внимание, что абстрактный класс может содержать не только абстрактные, но и обычные методы.

Раннее мы создавали класс Фигура, у которого был метод вычисления площади фигуры. Метод ничего не делал, так как невозможно вычислить площадь неизвестной фигуры. Поэтому, этот метод можно сделать абстрактным, а в классах, производных от Фигуры, переопределить данный метод.

 // абстрактный класс Фигура abstract class Figure < double dim1; double dim2; Figure(double a, double b) < dim1 = a; dim2 = b; >// абстрактный метод для вычисления площади abstract double area(); > // Клас Треугольник class Triangle extends Figure < Triangle(double a, double b) < super(a, b); >// переопределяем метод double area() < return dim1 * dim2 / 2; >> // В активности public void onClick(View view) < // Figure figure = new Figure(10, 10); // так нельзя Triangle triangle = new Triangle(10, 8); Figure figure; // так можно, так как объект мы не создаем figure = triangle; mInfoTextView.append("Площадь равна " + figure.area()); >

Фигура — это абстрактное понятие и мы не можем создать универсальный метод для вычисления площади. Поэтому мы создаём другой класс Треугольник и пишем код, вычисляющий площадь треугольника (загляните в учебник геометрии). Также вы можете создать новый класс Прямоугольник и написать свой код для вычисления площади этой фигуры.

Вам вряд ли придётся часто создавать абстрактные классы для своих приложений, но встречаться с ними вы будете постоянно, например, классы AsyncTask, Service и др.

Кот — понятие тоже абстрактное. А вот ваш любимец Васька или Мурзик уже конкретный шерстяной засранец. По запросу «abstract cat» мне выдало такую картинку. Всегда интересовал вопрос, где художники берут такую травку? (это был абстрактный вопрос).

Что такое абстрактный класс

Классная статья! Теперь дифференциация между интерфейсами и абстрактными классами стала понятнее после объяснение почему отказались от множественного наследования классов. Абстрактный класс — поведение и состояние концептуального класса. Интерфейс — просто описание поведения.

Dmitry Vidonov Уровень 29 Expert
1 сентября 2023
Хорошая статья!
26 августа 2023
Спасибо, все понятно и доступно объяснили)
chess.rekrut Уровень 25
21 августа 2023
Ant Уровень 27
22 июля 2023

Именно из-за такой «непонятки», когда объекту неясно, какое поведение он должен выбрать, создатели Java отказались от множественного наследования Даже не знаю, думаю пример не очень в статье, так как в большинстве источников сказано, что больше проблемы вызывают как раз обращение к переменным, при множественном наследовании. По сути те же интерфейсы могу создать неопределенную ситуацию с методами, но их(интерфейсы) все же добавили в язык.

Ислам Уровень 32
8 июня 2023
Евгений JackSun Уровень 32 Expert
7 марта 2023

У меня возник вопрос. Вот мы не можем наследовать от нескольких классов, потому что может возникнуть ситуация, когда в этих классах усть одинаковые названия методов с разной реализацией. Но что произойдёт, если мы реализуем несколько интерфейсов, у которых также есть одинаковые названия методов да ещё и с разной дефолтной реализацией?

10 декабря 2022

На самом деле — и это очень важная особенность — класс является абстрактным, если хотя бы один из его методов является абстрактным. Хоть один из двух, хоть один из тысячи методов — без разницы. ORACLE: An abstract class is a class that is declared abstract—it may or may not include abstract methods. Abstract classes cannot be instantiated, but they can be subclassed.

DmitryK #853142832 Уровень 26
29 апреля 2022

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

Абстрактный класс и интерфейс 😀

Кажется, когда-то давно читал похожее, когда опытные программисты возмущались вопросом на собеседовании: «в чем разница между абстрактным классом и интерфейсом». Тогда был джуном и возмущений не понял — ну знаешь же, ответь. 🙂

Сейчас сам столкнулся с похожим. Вопрос ставит в ступор. На работе занимаешься чем угодно, кроме сравнивания абстрактных классов с интерфейсами 🙁

Формулировка — сравнить эти две вещи, и что от тебя ждут ответ на это, кажется абсурдом и отключает. Может нужно ходить регулярно на собеседования для поддержания формы?

�� Подобається Сподобалось 1

До обраного В обраному 1

Найкращі коментарі пропустити

Работать и проходить собеседования — два разных занятия, требующих 2х разных, обычно не пересекающихся, наборов скилов.

Может нужно ходить регулярно на собеседования для поддержания формы?

Конечно нужно. Для поддержания себя в форме, выработки скила проходить собеседования и понимания того, что вообще на рынке происходит.

Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

190 коментарів

Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Мои рассуждения и вопрос знающим и понимающим, надеюсь на советы, поправки и подсказки для правильного понимания.

Можно сказать что интерфейс — набор требований, которым должны соответствовать абсолютно
разные объекты, т.к объекты разные, то и реализация требований для каждого объекта может сильно разнится. Плюс, если нет необходимости соответствовать этим требованиям, нету необходимости реализовывать этот интерфейс.
Пример как вижу я: объект Перевозчик может перевезти любой объект, который реализовывает интерфейс IVolumable: кукуруза сама знает как посчитать свой объем, утюг — сам, человек — сам. Объекты абсолютно разные, реализация разная, но для Перевозчика разницы нету — каждый IVolumable сообщил свой объем, и Перевозчик понимает как их перевезти, сколько их влезет, сколько это стоит. Кукуруза захочет что бы ее перевезли, она должна реализовать IVolumable, человек захочет что бы его перевезли, он должен реализовать IVolumable, утюгу никуда не надо, соответственно и имплементить этот интерфейс мы не будем.

Абстрактный класс — описывает (и просит следовать) общее поведение и свойства для группы схожих объектов-наследников. Ключевая фраза — схожих объектов. Между утюгом, человеком и кукурузой ничего схожего нету, также как и маловероятно что и них будет общий абстрактный класс.
Пример как вижу я: общий абстрактный класс AbstractIron, с единственным методом toIron(). Утюги есть разные, по-этому гладить будут по-разному: низкая температура, высокая, отпаривание и тп, но гладить они должны уметь все, соответственно все должны (пускай по-своему) реализовать toIron().
Общий абстрактный класс AbstractCorn, с единственным методом toRipe(). Разные сорта кукурузы будут созревать по-разному, но созревать они будут все.

Т.е. как это понимаю я — с архитектурной точки зрения (не вдаваясь в подробности копмиляции), интерфейс и абстрактный класс сравнивать некорректно, эти два понятия несут разное назначение. Они чем-то похожи: есть абстрактные методы; у них есть различия: наличие методов с имплементацией, возможность инстанциировать (и пр. особенности зависящие от ЯП).
Исходя из моего скудного опыта: интерфейс — более чаще используется в повседневной разработке, абстрактный класс — более чаще используется при написании фреймверков и каких-то библиотечных решений.
Интерфейс позволяет наделить разные объекты схожим/требуемым поведением, абстрактный класс задает «костяк» для группы схожих объектов.

Прошу поправить мои размышления. Ваш фидбек для меня важен. Возможно кому-то из начинающих также чем-то поможет.
Спасибо

Andrii Zaiats software engineer/architect в VITech 10.06.2020 23:22

Мій декан казав: «Нема дурних питань. Є дурні відповіді».

От ніколи такого питання сам не задавав, але вже кілька разів відповідав. І кожного разу відповіді були різними.
Зараз розумію шо питання прекрасне. Воно позволяє зрозуміти який тон співбесіді варто задавати далі і де будуть сильні і слабкі сторони.

Тільки уявіть скільки відповідей можна придумати. Наприклад:

1. В абстрактному класі можна мати реалізацію в методах, а в інтерфейсі — ні.

Шо ми з того можемо отрмати? Якшо ми Java джуна співбесідуємо то стає ясно шо про Java 8 він ше не прочитав.

2. В абстрактному класі можна мати поля і конструктор, а в інтерфейсі ні.

То вже трохи краще, але бачимо шо людина в першу чергу дивиться на нюанси мови, а не на концепцію. Такому можна довірити писати код, але робити дизайн ше, можливо, зарано.

3. Можна імплементити багато інтерфейсів, але розширяти лише один абстрактний клас.

З моєї точки зору то вже перший крок до ДЗЕНу (якшо не заблукає в тенетах технологій і зможе з часом думку цю розвинути). Можливо, при хорошому наставнику, можна виростити діамант.

4. Відповідь з розряду як від Oleksii Pavlov «хто я» і «шо я роблю» явно вказує — про нюанси мови багато говорити не треба. Маємо справу з художником, а не письменником. В таких випадках я розвішую вуха і стараюся сам чогось нового на співбесіді навчитися.

Правильних відповідей може бути багато. І кожна несе важливу інформацію про кандидата.

Добавить комментарий

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