Как сделать класс абстрактным

Обновлено: 08.07.2024

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

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

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

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

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

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

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

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

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

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

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

Abstract

Abstract

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

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

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

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

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

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

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

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

Смотрите, мы здесь определили одно поле model и три абстрактных метода: go, stop и draw. Абстракция в данном случае означает, что мы знаем что хотим от автомобиля, но пока незнаем как это будем делать. Своего рода, это некий набросок – абстракция, причем, абстракция на уровне класса и методов.

В действительности, если класс содержит хотя бы один абстрактный метод, то он должен быть объявлен как абстрактный. И, если мы попытаемся убрать ключевое слово abstract в определении класса, то возникнет ошибка. С другой стороны, если бы данный класс не содержал бы ни одного абстрактного метода, например, вот так:

То ключевое слово abstract можно как использовать, так и не использовать. Тогда в чем отличие этого абстрактного класса Car от такого же, но не абстрактного? В действительности, только одним: для абстрактных классов нельзя создавать экземпляры, то есть, вот такая строчка приведет к ошибке:

Но, если убрать слово abstract, то ошибки уже не будет. Конечно, это скорее искусственный пример, показывающий отличие в определении абстрактного и не абстрактного классов. В реальности, абстрактные классы, как правило, содержат абстрактные методы, как мы это сделали вначале. Но наряду с абстрактными методами можно записывать и обычные, например, так:

Здесь используется сеттер для задания поля model.

Ну, хорошо, мы можем объявлять абстрактные классы и методы, но зачем они нужны, если нельзя ни создавать объекты такого класса, ни вызывать такие методы? Все верно. И такие классы создаются исключительно для дальнейшего наследования и конкретизации их работы уже в дочерних классах. А абстракция позволяет сразу описать необходимые интерфейсы (то есть, методы), через которые в дальнейшем будут вызываться соответствующие переопределенные методы дочерних классов. Это часто очень удобно при реализации больших проектов, когда в целом определены информационные потоки через абстрактные классы и интерфейсы, а далее, создаются производные классы для их конкретного наполнения, реализации.

Итак, давайте тоже наполним конкретикой наш абстрактный класс Car. Для этого определим дочерний класс и назовем его, например, ToyotaCorolla. Если написать вот такие строчки:

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

Теперь никаких ошибок не будет и мы можем создать экземпляр этого класса:

Или, используя обобщенный тип ссылок на абстрактный класс:

И, далее, мы можем вызывать методы go, stop и draw, определенные в дочернем классе:

Давайте для примера добавим еще один дочерний класс ToyotaCamry:

Определим массив обобщенных ссылок в функции main:

Присвоим им экземпляры дочерних классов:

И вызовем общие методы базового класса Car, реализованные в дочерних классах:

Видите, благодаря тому, что в базовом классе прописаны виртуальные методы go, stop и draw, мы имеем возможность вызывать их, используя единый интерфейс – ссылки на экземпляры базового класса Car. Это еще один пример полиморфизма в ООП.

Но здесь у вас может возникнуть вопрос: зачем городить огород, придумывать абстрактный класс Car, когда все то же самое можно было сделать и с обычным классом Car. Да, все верно, например, можно прописать базовый класс в виде:

И все тоже работало бы. Но в такой реализации есть принципиальные отличия от предыдущей (с абстрактным классом). Во-первых, здесь нам приходится прописывать пустые реализации у методов и такие методы можно уже не переопределять в дочерних классах. Абстрактные же методы обязаны быть определены в производных классах и это, с одной стороны, гарантирует их требуемое наполнение, а с другой, помогает избежать ошибок, если программист забудет их определить.

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

Вот эти моменты обусловили появление абстрактных классов и методов в языке Java.

Путь кодера

Подвиг 1. Объявите абстрактный класс Geom для представления геометрических фигур с полями: width, color для определения толщины и цвета линии, а также с абстрактным методом draw() для рисования конкретного графического примитива. Затем, запишите дочерние классы Line, Rect, Ellipse для представления линий, прямоугольников и эллипсов. Определите в них поля для хранения координат этих фигур и метод draw() для их рисования. Создайте обобщенные ссылки Geom на объекты дочерних классов и вызовите у них метод draw().

Подвиг 2. Объявите абстрактный класс Recipes (рецепты) с полями: название, тип (вегетарианский/обычный). И абстрактными методами: showIngredients (показать ингредиенты), showRecipe (показать рецепт). Описать несколько дочерних классов: Salad (для салатов), Pizza (для пицц), Porridge (для каш). В каждом дочернем классе определить поле для списка ингредиентов (в виде строки) и описания самого рецепта (в виде строки). А также реализовать абстрактные методы базового класса Recipes. Создать несколько экземпляров дочерних классов и через общий интерфейс (в виде ссылок типа Recipes) вызвать методы showRecipe и showIngredients.

abstract class java

В продолжения статьи об классах и методах в java сегодня затронем тему абстрактного класса:

  • что такое абстрактный класс в java;
  • как его создать;
  • как пользоваться абстрактным классом;
  • и самое главное — зачем нужен данный вид классов.

Абстрактный класс — это класс, в объявлении которого есть ключевое слово abstract. Его отличие от обычного класса в том, что нельзя создать объект или экземпляр данного класса. Все остальное в абстрактном классе остается таким как и в обычном. У него есть методы. Только абстрактный класс может иметь абстрактные методы — у которых нет реализации, только объявление. Это означает, что абстрактный метод должен быть реализован в классе-наследнике. Для того чтобы полностью понимать картину абстрактный классов и методов нужно владеть таким понятием как ООП. Ведь абстрактные классы чаще всего используются при реализации наследования.

Теперь когда мы немного познакомились с теорией, предлагаю перейти к практике:

Выше реализован пример абстрактного класса. Как уже говорилось: чтобы класс стал абстрактным нужно добавить к его объявлению ключевое слово abstract.

Абстрактный класс может содержать как обычные, так и абстрактные методы. Давайте реализуем и те, и другие.

public abstract class AbstractClassExample

public abstract void abstractMethodExample ( ) ;

public void classicMethodExample ( ) <
System . out . println ( "Classic method realisation" ) ;
>
>

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

public abstract class AbstractClassExample

public abstract void abstractMethodExample ( ) ;

public void classicMethodExample ( ) <
System . out . println ( "Classic method realisation" ) ;
>
>

class AbstractClassRealization extends AbstractClassExample

@Override
public void abstractMethodExample ( ) <
System . out . println ( "Abstract method realizationg" ) ;
>

class Main <
public static void main ( String [ ] args ) <
AbstractClassRealization abstractClassRealization = new AbstractClassRealization ( ) ;
abstractClassRealization. abstractMethodExample ( ) ;
abstractClassRealization. classicMethodExample ( ) ;
>
>

Результатом выполнения кода будет:

результат выполнения абстрактного класса

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

public abstract class AbstractClassExample

public abstract void abstractMethodExample ( ) ;

public void classicMethodExample ( ) <
System . out . println ( "Classic method realisation" ) ;
>
>

class AbstractClassRealization extends AbstractClassExample

@Override
public void abstractMethodExample ( ) <
System . out . println ( "Abstract method realizationg" ) ;
>

public void classicMethodExample ( ) <
System . out . println ( "Classic overriden method" ) ;
>

class Main <
public static void main ( String [ ] args ) <
AbstractClassRealization abstractClassRealization = new AbstractClassRealization ( ) ;
abstractClassRealization. abstractMethodExample ( ) ;
abstractClassRealization. classicMethodExample ( ) ;
>
>

В примере выше сработает реализация переопределенного метода в наследнике.

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

public abstract class AbstractClassExample

public abstract void abstractMethodExample ( ) ;

public void classicMethodExample ( ) <
System . out . println ( "Classic method realisation" ) ;
>
>

class AbstractClassRealization extends AbstractClassExample

@Override
public void abstractMethodExample ( ) <
System . out . println ( "Abstract method realizationg" ) ;
>

public void classicMethodExample ( ) <
System . out . println ( "Classic overriden method" ) ;
>

class Main <
public static void main ( String [ ] args ) <
AbstractClassRealization abstractClassRealization = new AbstractClassRealization ( ) ;
abstractClassRealization. abstractMethodExample ( ) ;
abstractClassRealization. classicMethodExample ( ) ;

//мы создали переменную с типом абстрактного класса
AbstractClassExample abstractClassExample = new AbstractClassRealization ( ) ;
//но сработает всеравно метод класса наследника
abstractClassExample. classicMethodExample ( ) ;
>
>

Результатом выполнения кода будет:

результат выполнения кода

Данный или похожий пример очень часто можно увидеть в различных тестах. Здесь важно понимать, что будет выполняться метод экземпляра (new AbstractClassRealization()), а не метод типа (AbstractClassExample).

Еще очень часто на собеседованиях можно услышать вопрос: может ли обычный класс иметь абстрактный метод? Ответ: не может. Абстрактный класс может иметь абстрактный и обычный метод, но обычный класс не может иметь абстрактный метод.

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

как писать юнит тесты

Доброго времени суток!
Тема весьма сложная для начинающего, потому возник вопрос, для чего все-таки нужны абстрактные классы, наследование — это понятно, но зачем тут нужны абстрактные классы, покажите на примере, где это является необходимостью

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

Объявление

Нужно добавить ключевое слово abstract в объявление класса:

Теперь вы не можете создавать экземпляры MyAbstractClass. Таким образом, следующий код больше не действителен:

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

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

Вы объявляете их, добавляя ключевое слово abstract перед объявлением метода:

Информация об абстрактных методах:

  • Не имеет реализации.
  • У него просто есть подпись метода. Так же, как методы в интерфейсе.
  • Если у класса есть абстрактный метод, весь класс должен быть объявлен как абстрактный.
  • Не все методы в абстрактном классе должны быть абстрактными, может иметь и неабстрактные.
  • Подклассы абстрактного класса должны реализовывать (переопределять) все абстрактные методы его абстрактного суперкласса. Неабстрактные методы суперкласса просто наследуются как есть. Они также могут быть отменены, если это необходимо.

Вот пример подкласса:

Обратите внимание, как MySubClass должен реализовывать абстрактный метод abstractMethod() из своего абстрактного суперкласса MyAbstractClass.

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

Цель – функционировать как базовые классы, которые могут быть расширены подклассами для создания полной реализации. Например, представьте, что определенный процесс требует 3 шага:

  • Шаг до действия.
  • Действие.
  • Шаг после действия.

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

Обратите внимание, как метод action() является абстрактным. Подклассы MyAbstractProcess теперь могут расширять MyAbstractProcess и просто переопределять метод action().

Когда вызывается метод process() подкласса, выполняется полный процесс, включая stepBefore() и stepAfter() абстрактного суперкласса и метод action() подкласса.

Конечно, MyAbstractProcess не должен был быть абстрактным, чтобы функционировать как базовый класс. Метод action() также не должен быть абстрактным. Вы могли бы просто использовать обычный класс. Однако, создав метод для реализации абстрактного, а значит и класса, вы четко дадите понять его пользователям, что он не должен использоваться как есть. Вместо этого его следует использовать в качестве базового класса для подкласса, а абстрактный метод должен быть реализован в подклассе.

В приведенном выше примере не было реализации по умолчанию для метода action(). В некоторых случаях ваш суперкласс может ее иметь. Тогда вы можете не делать метод абстрактным. Вы все равно можете сделать суперкласс абстрактным, даже если он не содержит абстрактных методов.

Вот более конкретный пример, который открывает URL-адрес, обрабатывает его и впоследствии закрывает соединение с URL-адресом.

Обратите внимание, что processURLData() является абстрактным методом, а URLProcessorBase – абстрактным классом. Подклассы URLProcessorBase должны реализовывать processURLData(), потому он абстрактный.

Подклассы URLProcessorBase могут обрабатывать данные, загруженные с URL-адресов, не беспокоясь об открытии и закрытии сетевого подключения к URL-адресу. Это делается с помощью URLProcessorBase. Подклассам нужно только беспокоиться об обработке данных из InputStream, переданных методу processURLData(). Это облегчает реализацию классов, обрабатывающих данные из URL.

Вот пример подкласса:

Обратите внимание, как подкласс реализует только метод processURLData(), и ничего более. Остальной код унаследован от суперкласса URLProcessorBase.

Вот пример того, как использовать класс URLProcessorImpl:

Вызывается метод process(), который реализован в суперклассе URLProcessorBase. Этот метод, в свою очередь, вызывает processURLData() в классе URLProcessorImpl.

Шаблона проектирования Template

Пример, который я показал вам выше с классом URLProcessorBase, на самом деле является примером шаблона проектирования Template. Он обеспечивает частичную реализацию некоторого процесса, который подклассы могут выполнять при расширении базового класса Template.

В этом уроке, мы обсудим абстрактный класс и его особенности, связанные с объектно-ориентированными методами в PHP. Кроме того, мы изучим реализацию абстрактного класса разобрав несколько примеров.

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

Абстрактные классы — это классы, в которых хотя бы один метод является абстрактным. Методы, объявленные абстрактными, несут, по существу, лишь описательный смысл (имеют только имя и аргументы) и не имеют тела. Таким образом, мы не можем создавать объекты из абстрактных классов. Вместо этого нам нужно создать дочерние классы, которые добавляют код в тела методов и используют эти дочерние классы для создания объектов.

Объявление абстрактных классов

Чтобы объявить абстрактный класс, нам нужно использовать ключевое слово abstract перед именем класса:

Синтаксис

Объявление абстрактных методов

Когда вы добавляете ключевое слово abstract к объявлению метода, он становится абстрактным методом. И помните, абстрактные методы не имеют тела. Поэтому фигурные скобки <> не используются.

Пример

Правила абстракции

Когда дочерний класс наследуется от абстрактного класса, применяются следующие правила:

  • Дочерний класс должен переопределить (повторно объявить) все абстрактные методы.
  • Количество обязательных аргументов для методов должны быть таким же, как у абстрактного метода.

Например, в приведенном выше примере myMethod2 имеет два аргумента: $name и $age . У метода myMethod2 в дочернем классе должны быть те же аргументы:

Дочерний класс может иметь аргументы со значениями по умолчанию, если в абстрактном классе они не определены (Например, $country = 'Germany'):

Например, myMethod3 в абстрактном классе выше указывает на int . Поэтому дочерний метод подсказывает то же самое:

Видимость абстрактного метода Видимость дочернего метода
public public
protected protected или public, но не private

Не абстрактные методы в абстрактном классе

Неабстрактные методы могут быть определены в абстрактном классе. Эти методы будут работать так же, как обычные методы наследования.

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

Давайте расширим приведенный выше пример и включим в наш класс неабстрактный метод myMethod2:

Пример

Примечание: В этом основное отличие абстрактных классов от интерфейсов. Абстрактные классы могут иметь реальные методы, а интерфейсы могут иметь только объявления методов.

Пример абстрактного класса в PHP ООП

Родительский абстрактный класс:

Пример

В родительском классе объявлены метод __construct и свойство $name . Итак, дочерний класс автоматически получит их. Но greet() — это абстрактный метод, который должен быть определен во всех дочерних классах, и они должны возвращать строку.

Как создать дочерние классы из абстрактного класса?

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

Примечание: Дочерние классы, которые наследуются от абстрактных классов, должны добавлять тела к абстрактным методам.

Давайте создадим дочерние классы и определим в них абстрактный метод, унаследованный от родителя, greet():

Пример

Теперь мы можем создавать объекты из дочерних классов:

Пример

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

Пример

Результат выполнения кода:

Заключение

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

Читайте также: