Java что может содержать в себе абстрактный класс
Абстрактные классы и методы
Класс, содержащий абстрактные методы, называется абстрактным классом. Такие классы помечаются ключевым словом abstract.
Абстрактный метод не завершён. Он состоит только из объявления и не имеет тела:
По сути, мы создаём шаблон метода. Например, можно создать абстрактный метод для вычисления площади фигуры в абстрактном классе Фигура. А все другие производные классы от главного класса могут уже реализовать свой код для готового метода. Ведь площадь у прямоугольника и треугольника вычисляется по разным алгоритмам и универсального метода не существует.
Если вы объявляете класс, производный от абстрактного класса, но хотите иметь возможность создания объектов нового типа, вам придётся предоставить определения для всех абстрактных методов базового класса. Если этого не сделать, производный класс тоже останется абстрактным, и компилятор заставит пометить новый класс ключевым словом abstract.
Можно создавать класс с ключевым словом abstract даже, если в нем не имеется ни одного абстрактного метода. Это бывает полезным в ситуациях, где в классе абстрактные методы просто не нужны, но необходимо запретить создание экземпляров этого класса.
В тоже время абстрактный класс не обязательно должен иметь только абстрактные методы. Напомню ещё раз, что если класс содержит хотя бы один абстрактный метод, то он обязан быть сам абстрактным.
Создавать объект на основе абстрактного класса нельзя.
Абстрактный класс не может содержать какие-либо объекты, а также абстрактные конструкторы и абстрактные статические методы. Любой подкласс абстрактного класса должен либо реализовать все абстрактные методы суперкласса, либо сам быть объявлен абстрактным. Короче, я сам запутался. Пойду лучше кота поглажу.
Я вернулся. Давайте напишем пример для абстрактного класса.
Допустим, мы хотим создать абстрактный класс СферическийКонь и не менее идиотский класс СферическийКоньВВакууме, наследующий от первого класса.
Когда вы напишете такой код, то студия подчеркнёт второй класс красной волнистой линией и предложит реализовать обязательный метод, который определён в абстрактном классе.
Соглашаемся и дописываем в созданную заготовку свой код для метода.
В главной активности напишем код для щелчка кнопки.
Обратите внимание, что абстрактный класс может содержать не только абстрактные, но и обычные методы.
Раннее мы создавали класс Фигура, у которого был метод вычисления площади фигуры. Метод ничего не делал, так как невозможно вычислить площадь неизвестной фигуры. Поэтому, этот метод можно сделать абстрактным, а в классах, производных от Фигуры, переопределить данный метод.
Вам вряд ли придётся часто создавать абстрактные классы для своих приложений, но встречаться с ними вы будете постоянно, например, классы AsyncTask, Service и др.
Абстрактные классы в Java
Узнайте, как и когда использовать абстрактные классы как часть иерархии классов в Java.
1. Обзор
Есть много случаев при реализации контракта, когда мы хотим отложить некоторые части реализации, чтобы завершить их позже. Мы можем легко сделать это в Java с помощью абстрактных классов.
2. Ключевые понятия для абстрактных классов
Прежде чем углубиться в то, когда следует использовать абстрактный класс, давайте рассмотрим их наиболее релевантные характеристики :
Чтобы лучше понять эти концепции, мы приведем простой пример.
Пусть наш базовый абстрактный класс определит абстрактный API настольной игры:
Затем мы можем создать подкласс, реализующий метод play :
3. Когда следует использовать абстрактные классы
Теперь, давайте проанализируем несколько типичных сценариев, в которых мы должны предпочесть абстрактные классы интерфейсам и конкретным классам:
Обратите внимание, что повторное использование кода является очень веской причиной для использования абстрактных классов, пока сохраняется связь “is-a” в иерархии классов.
4. Пример Иерархии считывателей файлов
Чтобы более четко понять функциональность, которую абстрактные классы привносят в таблицу, давайте рассмотрим другой пример.
4.1. Определение базового абстрактного класса
Итак, если бы мы хотели иметь несколько типов считывателей файлов, мы могли бы создать абстрактный класс, который инкапсулирует то, что является общим для чтения файлов:
Обратите внимание, что мы сделали filePath защищенным, чтобы подклассы могли получить к нему доступ в случае необходимости. Что еще более важно, мы оставили кое-что незаконченным: как на самом деле разобрать строку текста из содержимого файла.
Наш план прост: хотя у каждого из наших конкретных классов нет специального способа хранения пути к файлу или просмотра файла, у каждого из них будет особый способ преобразования каждой строки.
4.2. Определение Подклассов
Естественная реализация-это, вероятно, та, которая преобразует содержимое файла в нижний регистр:
Или другой может быть тот, который преобразует содержимое файла в верхний регистр:
Как мы видим из этого простого примера, каждый подкласс может сосредоточиться на своем уникальном поведении без необходимости указывать другие аспекты чтения файлов.
4.3. Использование подкласса
Наконец, использование класса, который наследуется от абстрактного, ничем не отличается от любого другого конкретного класса:
5. Заключение
Абстрактные классы
— Привет, Амиго! Новая интересная тема.
— Да сегодня просто день интересных тем!!
— Помнишь ситуацию, когда мы ввели базовый класс ChessItem для упрощения всех классов шахматных фигур?
— Теперь представь, что у каждой фигуры есть метод, который занимается ее отрисовкой на экране. Вызываешь метод, и фигура сама себя рисует в своих текущих координатах. Удобно было бы вынести этот метод в базовый класс?
— Да. После того, что я узнал о полиморфизме, можно было бы вызывать метод отрисовки для всех фигур, независимо от их типа. Примерно так:
— Молодец. Именно так. А что бы отрисовал на экране метод draw самого класса ChessItem?
— Не знаю. Такой фигуры ведь в шахматах нет. Значит, и изображения у нее нет.
— Именно. Более того, создавать объекты типа ChessItem – не имеет смысла. Это не фигура из шахмат, всего лишь абстракция — класс, который мы сделали для удобства. Так работает абстракция из ООП: мы вынесли важные (общие для всех фигур) данные и методы в базовый класс, а их различия оставили в их классах.
Для такого случая в Java есть специальный тип классов – абстрактные классы. Вот четыре вещи, которые стоит помнить об абстрактных классах.
1) Абстрактный класс может содержать объявление метода без его реализации. Такой метод называется абстрактным.
2) Абстрактный метод помечается специальным ключевым словом abstract.
Если в классе есть хоть один абстрактный метод, класс тоже помечается ключевым словом abstract.
3) Создавать объекты абстрактного класса нельзя. Такой код просто не скомпилируется.
Код на Java | Описание |
---|---|
Этот код не скомпилируется | |
А так можно. |
4) Если ты наследовал свой класс от абстрактного класса, то нужно переопределить все унаследованные абстрактные методы — написать для них реализацию. Иначе такой класс тоже придется объявить абстрактным. Если в классе есть хотя-бы один нереализованный метод, объявленный прямо в нем или унаследованный от класса-родителя, то класс считается абстрактным.
То же и с абстрактным классом. Тот, кто написал этот класс, не хочет, чтобы создавались его объекты. Наоборот, он рассчитывает на то, чтобы от его абстрактного класса наследовались и переопределяли абстрактные методы.
— Все равно не понятно, зачем усложнять себе жизнь?
— Преимущество этого проявляется в больших проектах. Чем больше классов, тем чётче приходится очерчивать их роли. Ты увидишь преимущество этого, и уже в ближайшем будущем. Все через это проходят.
Абстрактный класс в Java
В продолжения статьи об классах и методах в java сегодня затронем тему абстрактного класса:
Абстрактный класс — это класс, в объявлении которого есть ключевое слово abstract. Его отличие от обычного класса в том, что нельзя создать объект или экземпляр данного класса. Все остальное в абстрактном классе остается таким как и в обычном. У него есть методы. Только абстрактный класс может иметь абстрактные методы — у которых нет реализации, только объявление. Это означает, что абстрактный метод должен быть реализован в классе-наследнике. Для того чтобы полностью понимать картину абстрактный классов и методов нужно владеть таким понятием как ООП. Ведь абстрактные классы чаще всего используются при реализации наследования.
Теперь когда мы немного познакомились с теорией, предлагаю перейти к практике:
Выше реализован пример абстрактного класса. Как уже говорилось: чтобы класс стал абстрактным нужно добавить к его объявлению ключевое слово abstract.
Абстрактный класс может содержать как обычные, так и абстрактные методы. Давайте реализуем и те, и другие.
public abstract class AbstractClassExample <
public abstract void abstractMethodExample ( ) ;
Класс, который унаследуется от примера выше должен обязательно реализовать абстрактный метод abstractMethodExample. Реализовывать обычный метод в классе-наследнике не обязательно. В случае, если наследник не реализует обычный метод абстрактного метода — выполняется реализация родителя.
public abstract class AbstractClassExample <
public abstract void abstractMethodExample ( ) ;
class AbstractClassRealization extends AbstractClassExample <
class Main <
public static void main ( String [ ] args ) <
AbstractClassRealization abstractClassRealization = new AbstractClassRealization ( ) ;
abstractClassRealization. abstractMethodExample ( ) ;
abstractClassRealization. classicMethodExample ( ) ;
>
>
Результатом выполнения кода будет:
В случае, если в наследнике переопределен обычный метод, будет выполняться его реализация.
public abstract class AbstractClassExample <
public abstract void abstractMethodExample ( ) ;
class AbstractClassRealization extends AbstractClassExample <
class Main <
public static void main ( String [ ] args ) <
AbstractClassRealization abstractClassRealization = new AbstractClassRealization ( ) ;
abstractClassRealization. abstractMethodExample ( ) ;
abstractClassRealization. classicMethodExample ( ) ;
>
>
В примере выше сработает реализация переопределенного метода в наследнике.
В самом начале мы говорили, что создать экземпляр абстрактного класса нельзя. Это верно. Но, можно создать переменную этого класса. Внимательно посмотрите на пример ниже.
public abstract class AbstractClassExample <
public abstract void abstractMethodExample ( ) ;
class AbstractClassRealization extends AbstractClassExample <
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. С большим познанием основ ооп и принципов построения систем, Вы сможете умело управлять различными видами классов. И, однажды, абстрактный класс сможет выручить в сложных ситуациях программирования и проектирования систем.
Доброго времени суток!
Тема весьма сложная для начинающего, потому возник вопрос, для чего все-таки нужны абстрактные классы, наследование — это понятно, но зачем тут нужны абстрактные классы, покажите на примере, где это является необходимостью
Здравствуйте. На первый взгляд: абстрактный класс можно заменить на интерфейс и это действительно так. НО! В абстрактном классе могут быть уже реализованные методы. Тогда как в интерфейсе идет только объявление методов. Сейчас, когда уже есть java11 в интерфейсе может быть один реализованный метод. В абстрактном классе же можно объявить и реализовать сколько угодно методов. Подкреплю теорию примером. Допустим у вас есть класс Animal в котором объявлены методы voice(), walk(), name(). Допустим первые 2 метода вы решили сделать абстрактными, а последний реализовать. Когда класс будет наследовать Animal он должен будет обязательно реализовать методы voice(), walk() так как они абстрактные, но метод name() ему реализовывать не обязательно. Допустим в данном методе будет выводиться строка «Я животное». Ваш товарищ по команде будет наследовать ваш абстрактный класс Animal и ему обязательно подсветит, что нужно реализовать методы voice(), walk(), а метод name() он будет реализовывать уже по усмотрению. Он может как переопределить такой метод, так и оставить реализацию родителя.
Разумеется, пример очень банальный, но на реальных и сложных проектах абстрактный класс часто приходит на выручку:)
Разница между абстрактными классами и интерфейсами
Интерфейс описывает только поведение. У него нет состояния. А у абстрактного класса состояние есть: он описывает и то, и другое.
Возьмем для примера абстрактный класс Bird и интерфейс Flyable :
Давай создадим класс птицы Mockingjay (сойка-пересмешница) и унаследуем его от Bird :
Как видишь, мы легко получаем доступ к состоянию абстрактного класса — к его переменным species (вид) и age (возраст).
Но если мы попытаемся сделать это же с интерфейсом, картина будет другой. Можем попробовать добавить в него переменные:
У нас даже не получится создать внутри интерфейса private-переменные. Почему? Потому что private-модификатор создали, чтобы скрывать реализацию от пользователя. А внутри интерфейса реализации нет: там и скрывать нечего.
Интерфейс только описывает поведение. Соответственно, мы не сможем реализовать внутри интерфейса геттеры и сеттеры. Такова природа интерфейса: он нужен для работы с поведением, а не состоянием.
В Java8 появились дефолтные методы интерфейсов, у которых есть реализация. О них ты уже знаешь, поэтому повторяться не будем.
Абстрактный класс связывает между собой и объединяет классы, имеющие очень близкую связь. В то же время, один и тот же интерфейс могут реализовать классы, у которых вообще нет ничего общего.
Вернемся к нашему примеру с птицами.
Наш абстрактный класс Bird нужен, чтобы на его основе создавать птиц. Только птиц и никого больше! Конечно, они будут разными.
С интерфейсом Flyable все обстоит по-другому. Он только описывает поведение, соответствующее его названию, — «летающий». Под определение «летающий», «способный летать» попадает много объектов, не связанных между собой.
Мы бы не смогли описать их с помощью абстрактного класса. У них нет общего состояния, одинаковых полей. Чтобы дать характеристику самолету, нам, наверное, понадобятся поля «модель», «год выпуска» и «максимальное количество пассажиров». Для Карлсона — поля для всех сладостей, которые он сегодня съел, и список игр, в которые он будет играть с Малышом. Для комара. э-э-э. даже не знаем… Может, «уровень надоедливости»? 🙂
Главное, что с помощью абстрактного класса описать их мы не можем. Они слишком разные. Но есть общее поведение: они могут летать. Интерфейс идеально подойдет для описания всего на свете, что умеет летать, плавать, прыгать или обладает каким-то другим поведением.
Классы могут реализовывать сколько угодно интерфейсов, но наследоваться можно только от одного класса.
Об этом мы уже говорили не раз. Множественного наследования в Java нет, а множественная реализация есть. Отчасти этот пункт вытекает из предыдущего: интерфейс связывает между собой множество разных классов, у которых часто нет ничего общего, а абстрактный класс создается для группы очень близких друг другу классов. Поэтому логично, что наследоваться можно только от одного такого класса. Абстрактный класс описывает отношения «is a».
Стандартные интерфейсы InputStream & OutputStream
Очень простой класс для записи примитивных типов Java и строк. Наверняка ты поймешь написанный код даже без объяснений:
Опять же, ты можешь самостоятельно «поиграть» с этим кодом и проверить, как он будет работать на реальных файлах твоего компьютера.