- Абстрактный класс java определение
- Кофе-брейк #140. Абстрактные классы и интерфейсы в Java
- Что такое интерфейс
- Когда использовать интерфейсы
- Переопределение метода интерфейса
- Постоянные переменные
- Методы по умолчанию
- Суть абстрактного класса
- Абстрактные методы в абстрактных классах
- Когда использовать абстрактные классы
- Различия между абстрактными классами и интерфейсами
Абстрактный класс java определение
У меня возник вопрос. Вот мы не можем наследовать от нескольких классов, потому что может возникнуть ситуация, когда в этих классах усть одинаковые названия методов с разной реализацией. Но что произойдёт, если мы реализуем несколько интерфейсов, у которых также есть одинаковые названия методов да ещё и с разной дефолтной реализацией?
На самом деле — и это очень важная особенность — класс является абстрактным, если хотя бы один из его методов является абстрактным. Хоть один из двух, хоть один из тысячи методов — без разницы. 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 есть концепция Интерфейса, которая сильно ослабляет зависимость Полиморфизма от Наследования. Благодаря Интерфейсу классы становятся полиморфными независимо от их родителя, и мы получаем Полиморфизм без ограничений Наследования.
На самом деле очень даже сомнительное доказательство того, что от множественного наследования отказались именно по той причине, которая указана в статье т.к следующий код:
public class Solution < public static void main(String[] args) < >public abstract class Human implements CanRun, CanSwim < >public interface CanRun < default void run()< System.out.println("run1"); >> public interface CanSwim < default void run()< System.out.println("run2"); >> >
даже не компилируется выделяя класс Human и подсвечивает следующую ошибку: «Human inherits unrelated defaults for run() from types CanRun and CanSwim» Думаю то же самое могло бы писаться при попытке множественного наследования, если бы в двух разных родителях был одинаковый метод. Поэтому слабо верится. То же касается и переменных. Сейчас можно создавать переменные в интерфейсах, и если создать две переменных с одинаковым именем, то при имплементации и попытке обращения к таким переменным компилятор выдаст ошибку. Так что учитывая то, что сейчас в интерфейсе можно делать то же самое что и в классе, то можно сказать что в джаве есть множественное наследование.
Кофе-брейк #140. Абстрактные классы и интерфейсы в Java
Источник: InfoWorld Сегодня вы узнаете, в каких случаях разработчику стоит использовать абстрактный класс, а в каких — интерфейс. Также мы определим разницу между этими элементами языка Java и выясним, как использовать их в программах. Абстрактные классы и интерфейсы достаточно распространены в коде Java и даже в самом Java Development Kit (JDK). Каждый из этих элементов служит своей цели:
- Интерфейс — это конструкция в языке Java, которая помогает реализовать абстрактные методы и статические константы.
- Абстрактные классы похожи на обычные классы, с тем отличием, что они могут включать абстрактные методы, то есть методы без тела. Абстрактные классы не могут быть созданы.
Многие разработчики считают, что интерфейсы и абстрактные классы похожи, но на самом деле это не совсем так. Давайте рассмотрим основные различия между ними.
Что такое интерфейс
По своей сути, интерфейс — это контракт, поэтому он зависит от реализации, которая определяет цель его создания. Интерфейс не может использовать изменяемые переменные экземпляра, он может использовать только конечные переменные.
Когда использовать интерфейсы
Интерфейсы очень полезны для разделения кода и реализации полиморфизма. Мы можем это увидеть на примере в JDK с интерфейсом List :
public interface List extends Collection
Как вы, вероятно, заметили, этот код хотя и краткий, но весьма описательный. Мы можем легко увидеть сигнатуру метода, которая будет использоваться для реализации методов в интерфейсе с использованием конкретного класса. Интерфейс List содержит контракт, который можно реализовать классами ArrayList , Vector , LinkedList и другими. Чтобы использовать полиморфизм, мы можем просто объявить тип нашей переменной с помощью List , а затем выбрать любой из доступных экземпляров. Вот еще один пример:
List list = new ArrayList(); System.out.println(list.getClass()); List list = new LinkedList(); System.out.println(list.getClass());
В данном случае методы реализации для ArrayList , LinkedList и Vector различаются, что является отличным сценарием для использования интерфейса. Если вы заметили, что многие классы принадлежат родительскому классу с одними и теми же действиями методов, но с разным поведением. В таких ситуациях рекомендуется использовать интерфейс. Далее давайте рассмотрим несколько вариантов применения интерфейсов.
Переопределение метода интерфейса
Как мы уже знаем, интерфейс — это своего рода контракт, который должен быть реализован конкретным классом. Методы интерфейса неявно абстрактны и требуют конкретной реализации класса. Вот пример:
public class OverridingDemo < public static void main(String[] args) < Challenger challenger = new JavaChallenger(); challenger.doChallenge(); >> interface Challenger < void doChallenge(); >class JavaChallenger implements Challenger < @Override public void doChallenge() < System.out.println("Challenge done!"); >>
Обратите внимание, что методы интерфейса неявно абстрактные. Это означает, что нам не нужно явно объявлять их абстрактными.
Постоянные переменные
Еще одно правило, которое следует помнить, заключается в том, что интерфейс может содержать только постоянные переменные. Вот пример:
Тут обе переменные являются неявными final и static . Это означает, что они являются константами, не зависят от экземпляра и не могут быть изменены. А теперь мы попытаемся изменить переменные в интерфейсе Challenger , скажем, вот так:
Challenger.number = 8; Challenger.name = "Another Challenger";
Методы по умолчанию
Когда в Java 8 появились методы по умолчанию, некоторые разработчики думали, что они будут такими же, как абстрактные классы. Однако это не так, потому что интерфейсы не могут иметь состояние. Метод по умолчанию может иметь реализацию, а абстрактные методы — нет. Методы по умолчанию являются результатом инноваций с лямбда-выражениями и потоками, но мы должны использовать их осторожно. Метод в JDK, использующий метод по умолчанию, — это forEach() , который является частью интерфейса Iterable . Вместо того, чтобы копировать код в каждую реализацию Iterable , мы можем просто повторно использовать метод forEach :
default void forEach(Consumer action) < // Code implementation here.
Любая реализация Iterable может использовать метод forEach() , не требуя новой реализации метода. Затем мы можем повторно использовать код с методом по умолчанию. Давайте создадим наш собственный метод по умолчанию:
public class DefaultMethodExample < public static void main(String[] args) < Challenger challenger = new JavaChallenger(); challenger.doChallenge(); >> class JavaChallenger implements Challenger < >interface Challenger < default void doChallenge() < System.out.println("Challenger doing a challenge!"); >>
В отношении методов по умолчанию важно отметить, что каждый такой метод нуждается в реализации. Метод по умолчанию не может быть статическим. А теперь перейдем к абстрактным классам.
Суть абстрактного класса
Абстрактные классы могут иметь состояние с переменными экземпляра. Это означает, что переменная экземпляра может использоваться и изменяться. Вот пример:
public abstract class AbstractClassMutation < private String name = "challenger"; public static void main(String[] args) < AbstractClassMutation abstractClassMutation = new AbstractClassImpl(); abstractClassMutation.name = "mutated challenger"; System.out.println(abstractClassMutation.name); >> class AbstractClassImpl extends AbstractClassMutation
Абстрактные методы в абстрактных классах
Как и интерфейсы, абстрактные классы могут иметь абстрактные методы. Абстрактный метод — это метод без тела. В отличие от интерфейсов, абстрактные методы в абстрактных классах должны быть явно объявлены как абстрактные. Перед вами пример:
public abstract class AbstractMethods
public abstract class AbstractMethods
Когда использовать абстрактные классы
Абстрактный класс рекомендуется использовать, когда вам нужно реализовать изменяемое состояние. Например, Java Collections Framework включает класс AbstractList , который использует состояние переменных. В тех случаях, когда вам не нужно поддерживать состояние класса, обычно лучше использовать интерфейс.
Различия между абстрактными классами и интерфейсами
- Может иметь только конечные статические переменные. Интерфейс никогда не может изменить свое собственное состояние.
- Класс может реализовывать несколько интерфейсов.
- Может быть реализован с помощью ключевого слова implements. Интерфейс может расширять другой интерфейс.
- Для методов можно использовать только статические конечные поля, параметры или локальные переменные.
- Только функциональные интерфейсы могут использовать функцию лямбда в Java.
- Не может иметь конструктор.
- Может иметь абстрактные методы.
- Может иметь методы по умолчанию и статические (представлены в Java 8).
- Может иметь частные методы с реализацией (представлено в Java 9).
- Могут иметь любые экземпляры или статические переменные, изменяемые или неизменяемые.
- Класс может расширять только один абстрактный класс.
- Могут иметь экземпляр изменяемых полей, параметров или локальных переменных.
- Абстрактные классы только с одним абстрактным методом не могут использовать лямбда-выражения.
- Могут иметь конструктор.
- Могут иметь любые методы.