Что такое абстрактный класс в java
а если класс имплемитирует два интерфейса у обоих которых имеется метод с одинакоавм названием , как в примере пустб будеь public void on()?
Максим Li Уровень 36
12 ноября 2023
Хорошая статья!
Islam Yunusov Уровень 29
20 сентября 2023
Классная статья! Теперь дифференциация между интерфейсами и абстрактными классами стала понятнее после объяснение почему отказались от множественного наследования классов. Абстрактный класс — поведение и состояние концептуального класса. Интерфейс — просто описание поведения.
Dmitry Vidonov Уровень 29 Expert
1 сентября 2023
Хорошая статья!
26 августа 2023
Спасибо, все понятно и доступно объяснили)
chess.rekrut Уровень 25
21 августа 2023
Ant Уровень 29
22 июля 2023
Именно из-за такой «непонятки», когда объекту неясно, какое поведение он должен выбрать, создатели Java отказались от множественного наследования Даже не знаю, думаю пример не очень в статье, так как в большинстве источников сказано, что больше проблемы вызывают как раз обращение к переменным, при множественном наследовании. По сути те же интерфейсы могу создать неопределенную ситуацию с методами, но их(интерфейсы) все же добавили в язык.
Ислам Уровень 33
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.
Что такое абстрактный класс в java
Кроме обычных классов в Java есть абстрактные классы . Абстрактный класс похож на обычный класс. В абстрактном классе также можно определить поля и методы, но в то же время нельзя создать объект или экземпляр абстрактного класса. Абстрактные классы призваны предоставлять базовый функционал для классов-наследников. А производные классы уже реализуют этот функционал.
При определении абстрактных классов используется ключевое слово abstract :
public abstract class Human < private String name; public String getName() < return name; >>
Но главное отличие состоит в том, что мы не можем использовать конструктор абстрактного класса для создания его объекта. Например, следующим образом:
Human h = new Human();
Кроме обычных методов абстрактный класс может содержать абстрактные методы . Такие методы определяются с помощью ключевого слова abstract и не имеют никакой реализации:
public abstract void display();
Производный класс обязан переопределить и реализовать все абстрактные методы, которые имеются в базовом абстрактном классе. Также следует учитывать, что если класс имеет хотя бы один абстрактный метод, то данный класс должен быть определен как абстрактный.
Зачем нужны абстрактные классы? Допустим, мы делаем программу для обслуживания банковских операций и определяем в ней три класса: Person, который описывает человека, Employee, который описывает банковского служащего, и класс Client, который представляет клиента банка. Очевидно, что классы Employee и Client будут производными от класса Person, так как оба класса имеют некоторые общие поля и методы. И так как все объекты будут представлять либо сотрудника, либо клиента банка, то напрямую мы от класса Person создавать объекты не будем. Поэтому имеет смысл сделать его абстрактным.
public class Program < public static void main(String[] args) < Employee sam = new Employee("Sam", "Leman Brothers"); sam.display(); Client bob = new Client("Bob", "Leman Brothers"); bob.display(); >> abstract class Person < private String name; public String getName() < return name; >public Person(String name) < this.name=name; >public abstract void display(); > class Employee extends Person < private String bank; public Employee(String name, String company) < super(name); this.bank = company; >public void display() < System.out.printf("Employee Name: %s \t Bank: %s \n", super.getName(), bank); >> class Client extends Person < private String bank; public Client(String name, String company) < super(name); this.bank = company; >public void display() < System.out.printf("Client Name: %s \t Bank: %s \n", super.getName(), bank); >>
Другим хрестоматийным примером является система геометрических фигур. В реальности не существует геометрической фигуры как таковой. Есть круг, прямоугольник, квадрат, но просто фигуры нет. Однако же и круг, и прямоугольник имеют что-то общее и являются фигурами:
// абстрактный класс фигуры abstract class Figure < float x; // x-координата точки float y; // y-координата точки Figure(float x, float y)< this.x=x; this.y=y; >// абстрактный метод для получения периметра public abstract float getPerimeter(); // абстрактный метод для получения площади public abstract float getArea(); > // производный класс прямоугольника class Rectangle extends Figure < private float width; private float height; // конструктор с обращением к конструктору класса Figure Rectangle(float x, float y, float width, float height)< super(x,y); this.width = width; this.height = height; >public float getPerimeter() < return width * 2 + height * 2; >public float getArea() < return width * height; >>
Что такое абстрактные классы и методы в 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, нужно держать в уме некоторые наилучшие практики. Вот некоторые рекомендации, которые помогут вам эффективно пользоваться этими мощными инструментами:
- Пользуйтесь абстрактными классами, чтобы моделировать иерархии взаимосвязанных классов: при помощи абстрактных классов очень удобно представить группу таких взаимосвязанных классов, которые совместно используют некий общий функционал. Создавая абстрактный класс, который определяет общие методы и свойства, вы тем самым избегаете дублирования, повышаете модульность вашего кода и облегчаете его поддержку.
- Пользуйтесь абстрактными методами, чтобы определять общее поведение: абстрактные методы полезны в тех случаях, когда требуется навязать конкретное поведение сразу для множества субклассов. Определяя абстрактный метод в абстрактном классе, вы можете гарантировать, что все субклассы (каждый по-своему) будут реализовывать одно и то же поведение.
- Не переборщите с абстрактными классами и методами: притом, что абстрактные классы и методы могут быть довольно мощными, важно не прибегать к ним сверх меры. Вообще, следует создавать абстрактный класс или метод только в том случае, когда на то есть явная причина. Если слишком активно ими пользоваться, то код может излишне усложниться, и его станет тяжелее поддерживать.
- Придерживайтесь соглашений об именованиях: подбирая имена для абстрактных классов и методов, важно придерживаться стандартных соглашений об именованиях, действующих в Java. Именем абстрактного класса должно быть абстрактное существительное (напр., “Shape”), а имена абстрактных методов должны быть глаголами (напр. “draw”).
- Документируйте ваш код: как и при работе с любым кодом, абстрактные классы и методы важно документировать, чтобы они были понятнее другим разработчикам. Снабжайте код чёткими и краткими комментариями, которые поясняли бы смысл поведения каждого класса и метода, а также их назначение.
Заключение
Итак, абстрактные классы и методы – это мощные инструменты для реализации абстракций в Java. Умело пользуясь ими, вы сможете создавать более модульный и удобный в поддержке код, который проще понимать и расширять. Если вы моделируете иерархии взаимосвязанных классов или определяете общее поведение, которое должно реализовываться сразу во множестве субклассов, то вам в этом могут особенно помочь абстрактные классы и методы. Пользуясь рекомендованными практиками, рассмотренными выше, вы сможете освоить этот важный аспект программирования на Java.
Часто задаваемые вопросы
• Могут ли у абстрактных классов быть конструкторы?
Да, у абстрактных классов могут быть конструкторы. Правда, их нельзя напрямую инстанцировать, поэтому их конструкторы обычно вызываются конструкторами их субклассов.
• Могут ли абстрактные классы реализовывать интерфейсы?
Да, абстрактные классы могут реализовывать интерфейсы, это могут делать вообще любые классы. Эта возможность может пригодиться, если вы хотите предоставить некое общее поведение сразу для нескольких классов, так, чтобы они реализовывали один и тот же интерфейс.
• Могут ли абстрактные методы быть статическими?
Нет, абстрактные методы не могут быть статическими, так как для их работы требуется вызвать экземпляр класса. Правда, статические методы могут вызывать абстрактные методы, если они реализованы в конкретных субклассах.
• Могут ли абстрактные классы быть финальными?
Нет, абстрактные классы не могут быть финальными, так как они предназначены именно для расширения субклассами. Если сделать абстрактный класс финальным, то такое расширение будет исключено.
• Когда следует использовать абстрактные классы вместо интерфейсов?
Абстрактные классы хорошо вам подойдут, если вы хотите предоставить некоторый общий функционал для множества классов, входящих в общую иерархию. Интерфейсы лучше подходят для определения такого набора, методы из которого разные классы могут реализовывать независимо. Правило такое: пользуйтесь абстрактными классами, когда хотите предоставить базовую реализацию для группы взаимосвязанных классов. Интерфейсы уместнее, когда нужно определить группу методов для реализации разрозненными классами, в каждом по-своему.
- Блог компании Издательский дом «Питер»
- Java
- Совершенный код
- ООП
Абстрактные классы в Java и их отличия от интерфейсов: кратко и без воды
Смотрим на примерах, что такое абстрактный класс, когда лучше использовать интерфейсы и что такое абстрактные методы.
Иллюстрация: Dana Moskvina / Skillbox Media
Паша Лебедев
Пишет на Java. Верит в Agile. Пьёт много кофе и не любит грязный код.
Абстрактный класс — это класс, который содержит методы без реализации. Но зачем он такой нужен? Давайте разбираться.
Представим, что нам нужно описать несколько животных — и у каждого будет свой класс. Мы соберём их характеристики, опишем в полях и методах. У некоторых животных характеристики будут совпадать — например, и у гепарда, и у коня 4 ноги. А у некоторых — не совпадут: кролик ест траву, а тигр — других животных.
Однако, несмотря на несовпадение, мы можем выделить шаблонные характеристики: количество лап, издаваемый звук, приём пищи, передвижение. Эти шаблонные характеристики мы можем собрать в одном месте — абстрактном классе «Животное» и указать компилятору, что наполним их конкретными данными и поведением позже — в классах отдельных животных или групп животных.
Так на практике реализуется абстракция — процесс выделения наиболее важных характеристик объекта и информации об объекте. То есть мы обобщаем основную информацию о свойствах разных предметов или объектов и оставляем только самое важное, а менее важным пренебрегаем.
При этом абстрактным объект класса «Животное» создать нельзя — ведь в природе «просто животного» не существует, есть только волки, лисы, бегемоты и прочие слоны.
Простыми словами о том, что такое абстракция, рассказали в одной из статей большого руководства по объектно-ориентированному программированию. Там вы найдете множество примеров использования абстрактных классов и интерфейсов.
Давайте рассмотрим пример абстрактного класса в Java.
public abstract class Animal < Integer countOfLegs; Double weight; String color; public abstract void run( ); public void eat( ) < System.out.println("Animal says nyam-nyam"); > >
Как вы видите, абстрактный класс очень похож на обычный класс. Чтобы сделать класс абстрактным, нам нужно добавить ключевое слово abstract в описание класса и в методы, которые мы хотим оставить абстрактными, — то есть определить уже в конкретных классах (медведь, лиса, лягушка).
В абстрактном классе мы можем описать некоторые поля, которые будут отражать определённые свойства объекта или добавить обычный метод с реализацией по умолчанию.
Именно так мы и сделали в примере выше: добавили переменные для веса, цвета и количества ног у животного, а также описали два метода: run («бежать») и eat («кушать»). В нашем случае метод run — абстрактный, а у метода eat есть реализация по умолчанию. Это значит, что в классах, которые наследуют от Animal, мы обязаны добавить определение метода run, а переопределять или нет метод eat, зависит от наших задач и желания.
Теперь давайте попробуем создать класс на основе абстрактного класса. Пусть это будет класс, описывающий собаку.
public class Dog extends Animal < @Override public void run() < System.out.println("Dog says gaf-gaf"); > >
Здесь extends Animal означает, что мы наследуем класс Animal. Как только мы создадим пустой класс Dog, компилятор сразу подсветит его красным и выведет такое сообщение:
Error: (3, 8) java: com.company.Dog is not abstract and does not override abstract method run () in com.company.Animal
Это значит, что мы обязаны переопределить метод run() — что мы и сделали с помощью аннотации @Override.
Теперь давайте создадим объект класса Dog. Как мы видим, после его создания нам доступны все переменные и методы из класса Animal. Попробуем вызвать eat и run.
public static void main(String[] args) < Dog scooby = new Dog(); scooby.eat(); scooby.run(); >
Вот что мы увидим в консоли:
Animal says nyam-nyam
Dog says gaf-gaf
Итак, давайте выделим важные моменты:
- Мы не можем создавать объекты абстрактных классов — но в этом и нет смысла.
- В абстрактный класс можно добавлять методы с реализацией по умолчанию.
- Если мы наследуемся от абстрактного класса, то мы обязаны переопределить все абстрактные методы родительского класса (кроме тех, которые имеют реализацию по умолчанию) или сделать весь дочерний класс абстрактным.
- Абстрактные методы не имеют тела.
Больше рецептов на Java — в нашей базе знаний.
Отличия абстрактного класса и интерфейса
На собеседованиях часто задают вопрос, чем отличаются абстрактные классы и интерфейсы. Вот их основные отличия:
- Интерфейсы описывают только часть функциональности объекта — определённые признаки. Абстрактный класс же может описывать целую категорию разных объектов, а его характеристики имеют право наследовать только те объекты, которые являются частью этой категории. Например, собаки и волки — часть общей категории «Животные», а интерфейс, описывающий умение бегать, может реализовать и человек, и робот, и собака.
- Интерфейс описывает только поведение (методы), и у него нет полей. Точнее, есть возможность их объявить, но они будут public static final. В то же время абстрактный класс может содержать классические поля, которые будут принадлежать разным объектам.
- Наследник абстрактного класса обязан наследовать все его составляющие, а интерфейс создан только для реализации (имплементирования). Поэтому в Java мы можем наследовать класс только от одного класса, а на реализацию интерфейсов внутри одного класса ограничений нет.
Когда использовать абстрактный класс, а когда — интерфейс
Интерфейсы и абстрактные классы — это разные инструменты, разработанные для разных целей, хотя у них и есть общие черты.
Когда лучше использовать абстрактные классы:
- Вы хотите избежать дублирования кода, реализуя несколько тесно связанных классов из одной семантической категории.
- Классы, которые будут расширять ваш абстрактный класс, имеют много общих свойств и будут реализовывать много похожих методов.
- Наследуемый класс используется в отношении IS-A — то есть класс-наследник только расширяет функциональность абстрактного класса.
- Проект уже частично написан, а вы знаете, что выбранные классы будут часто меняться и дополняться новыми методами и полями. То есть поддерживать абстрактный класс и дополнять его намного проще, чем проектировать интерфейс и добавлять его новые методы во все места в коде, где они должны реализовываться.
Когда лучше использовать интерфейсы:
- Вам нужно описать определённую логику, которую должны поддерживать не связанные между собой объекты.
- Вам нужно привести к одному типу группу объектов и гарантировать схожую функциональность.
- Вам необходимо добавить какой-то маркер, который будет говорить о том, что выбранные классы поддерживают определённую логику.
- Вы хотите использовать множественное наследование типа.
Это лишь базовые и самые распространённые ситуации. Решая конкретные задачи, лучше советоваться с более опытными разработчиками или принимать самостоятельное решение.
Заключение
В этой статье мы с вами познакомились с понятием абстрактного класса, разобрались, для чего используются абстрактные классы, научились реализовывать их и проанализировали, в каких ситуациях лучше использовать интерфейсы, а в каких — абстрактные классы.
Читайте также:
- Что такое класс в Java
- Как разработчик на C++ превратил свой пет-проект в прибыльный стартап
- Основные принципы ООП: большой гайд по объектно-ориентированному программированию