JavaRush /Java блог /Random /Кофе-брейк #95. Как решить проблему множественного наслед...

Кофе-брейк #95. Как решить проблему множественного наследования в Java

Статья из группы Random
Источник: FreeCodeCamp Java — один из самых популярных объектно-ориентированных языков программирования, используемых сегодня. Поскольку он не зависит от платформы, вы можете найти Java-приложения на всех типах устройств и в каждой операционной системе. А поскольку Java относительно легко выучить, это один из языков, который осваивают многие программисты. Важная особенность Java, с которой вы должны быть знакомы, — это наследование классов. Наследование позволяет оптимизировать код, облегчая повторное использование классов. Когда вы можете повторно использовать код, который уже был протестирован и отлажен, жизненный цикл разработки программного обеспечения становится короче и менее затратным. Кофе-брейк #95. Как решить проблему множественного наследования в Java - 1Хотя теоретически это простая концепция, кодирование отношений наследования требует внимания к деталям. Особенно в отношении множественного наследования, когда один дочерний класс наследует свойства от нескольких родительских классов. Java отвергает множественные отношения наследования, потому что они создают неоднозначность, но есть несколько способов добиться многих из тех же эффектов, если вы знаете, что делать. В этой статье мы рассмотрим проблемы с множественным наследованием и обсудим альтернативные варианты кодирования на Java.

Терминология наследования

Иногда, чтобы стать успешным программистом, вам нужно научиться решать проблемы, чтобы найти обходные пути для общих ошибок или проблем. Это необходимая часть безопасного и умного кодирования. Одна из таких проблем связана с множественным наследованием (точнее, его отсутствием) в Java. Кофе-брейк #95. Как решить проблему множественного наследования в Java - 2Чтобы полностью понять наследование в Java, вам необходимо ознакомиться с базовой терминологией наследования объектно-ориентированного программирования (ООП).
  • Классы — это фундаментальная структура шаблона в объектно-ориентированных языках программирования. Класс определяет общие свойства для группы объектов.
  • Родительский класс: также известный как базовые классы или суперклассы. Родительский класс — это расширяемый класс, который предоставляет функции дочернему классу. Он допускает возможность повторного использования. Определения и функции родительского класса повторно используются при создании дочерних классов.
  • Дочерний класс: более обобщенно называемый подклассом, дочерний класс наследует функции от другого класса. Дочерние классы — это расширенные или производные классы.
  • Наследование: отношения между родительским и дочерним классами.

Типы наследования ООП

Сегодня используется множество популярных объектно-ориентированных языков программирования, включая Java, C ++ , JavaScript, Python, PHP, Ruby и Perl. Хотя наследование является общей концепцией для этих языков ООП, не все типы наследования существуют в каждом из этих языков. Крайне важно знать общие типы наследования и ограничения на наследование на конкретном языке, который вы используете. Чем больше вы знаете о наследовании, тем более эффективным разработчиком вы станете. Типы наследования, поддерживаемые Java, включают:
  • Одноуровневое наследование: когда дочерний класс наследует функции от единственного родительского класса.
  • Многоуровневое наследование: это многоуровневая форма одноуровневого наследования. При многоуровневом наследовании дочерний класс также может выступать в качестве родительского класса для других дочерних классов. Отношения между каждым уровнем линейны — никакие ветви не выходят выше, чем при множественном наследовании. В этом случае конечный дочерний класс имеет функции со всех уровней выше.
  • Иерархическое наследование: противоположность множественного наследования. В иерархическом наследовании единственный родительский класс имеет более одного дочернего класса. Таким образом, вместо того, чтобы иметь ветви над ним, он разветвляется внизу.
  • Гибридное наследование: как следует из названия, гибридное наследование представляет собой комбинацию других типов наследования.
В дополнение к типам наследования, указанным выше, существуют другие типы, которые Java не поддерживает.
  • Множественное наследование: при множественном наследовании дочерний класс имеет более одного родительского класса. Хотя Java и JavaScript не поддерживают множественное наследование, такие языки ООП, как C ++, поддерживают.
  • Многопутевое наследование: гибрид множественного, многоуровневого и иерархического наследования, при многопутевом наследовании дочерний класс наследует свои характеристики и функции от родительского класса и нескольких дочерних классов родительского класса. Поскольку многопутевое наследование основано на множественном наследовании, Java не поддерживает его использование.

Почему Java не поддерживает множественное наследование

Основная проблема множественного наследования заключается в том, что оно может создавать неоднозначности в дочерних классах. В обзорном техническом документе 1995 года ведущий дизайнер Java Джеймс Гослинг заявил, что проблемы с множественным наследованием были одной из причин создания Java. Сложности, присущие множественному наследованию, наиболее отчетливо видны в проблеме алмаза. В задаче “ромб” родительский класс A имеет два различных дочерних класса B и C; то есть дочерние классы B и C расширяют класс A. Кофе-брейк #95. Как решить проблему множественного наследования в Java - 3Теперь мы создаем новый дочерний класс D, который расширяет как класс B, так и класс C. Обратите внимание, что у нас есть множественное наследование (D расширяет B и C), иерархическое наследование (B и C расширяют A) и многоуровневое наследование (D расширяет A, B и C). В проблеме ромба дочерние классы B и C наследуют метод от родительского класса A. И B, и C переопределяют унаследованный метод. Но новые методы в B и C противоречат друг другу. Окончательный дочерний класс D наследует два независимых и конфликтующих метода от своих нескольких родителей B и C. Неясно, какой метод класса D следует использовать, поэтому возникает двусмысленность. Другие языки программирования ООП реализуют различные методы решения неоднозначности множественного наследования.

Как решить проблему множественного наследования в Java

То, что множественное наследование проблематично, не означает, что оно бесполезно. Есть много ситуаций, когда вы можете захотеть, чтобы один класс имел функции из нескольких других классов. Только подумайте об автомобиле Tesla Roadster, который вы купите, когда станете чрезвычайно успешным разработчиком программного обеспечения. Его технические характеристики основаны как на классе спортивных автомобилей, так и на классе электромобилей. Еще один пример: браузер, через который вы читаете эту статью. В нем есть функции из класса решений для обеспечения конфиденциальности данных в интернете и из общего класса интернет-браузеров. Но вы не можете расширить несколько классов в Java. Так как же этот язык справляется с проблемой множественного наследования? Java использует структуры, называемые интерфейсами. Интерфейсы — это абстрактные типы, которые определяют поведение для реализации классами. Поскольку они абстрактны, интерфейсы не содержат подробных инструкций по их поведению. Вместо этого классы предоставляют конкретные реализации поведения интерфейса. Интерфейсы имеют несколько определяющих характеристик:
  • В отличие от классов, вы не создаете экземпляры интерфейсов. Вместо этого классы реализуют интерфейсы.
  • Интерфейсы содержат только общедоступные определения констант и заголовки методов.
  • Интерфейсы могут расширять только другие интерфейсы, но не классы.
  • Интерфейсы могут расширять несколько интерфейсов, а классы могут реализовывать несколько интерфейсов.
Теперь мы можем эффективно обойти проблему ромба с помощью интерфейсов. Вспоминая, что только интерфейсы могут расширять только другие интерфейсы и любой класс, которому требуется несколько характеристик наследования, должен реализовывать несколько интерфейсов, мы можем переопределить классы проблем с ромбами. То, что раньше было классами A, B и C, теперь становится интерфейсами A, B и C. Интерфейсы B и C по-прежнему расширяют интерфейс A, но ни в одном из этих интерфейсов нет конкретных функций, только определенные поведения. Класс D остается классом, который отвечает за конкретную реализацию поведения, обнаруженного в интерфейсах B и C. Обратите внимание на одно ключевое различие: класс D не расширяет интерфейсы B и C. Вместо этого он их реализует. Таким образом, у вас фактически нет множественного наследования. Вместо этого вы просто переосмыслили проблему.

Заключение

Понимание наследования необходимо любому эффективному Java-разработчику. Также не менее важно знать ограничения наследования и встроенный обходной путь Java для традиционных проблем с множественным наследованием. Изучение того, как создавать интерфейсы для воссоздания эффектов множественного наследования в Java, повысит вашу эффективность и возможности найма.
Комментарии (1)
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ
Александр Уровень 41
7 октября 2021
Ну т.е. в Java проблема множественного наследования в классах не решена, а заменена на множественное наследование интерфейсов, что есть не совсем то или совсем не то. Кроме этого когда мы реализуем два интерфейса у которых есть метод, который имеет в них полностью идентичную сигнатуру, мы не можем реализовать в классе каждый из этих методов отдельно, а вынуждены реализовать один общий метод в классе для обоих интерфейсов. Также есть проблема, когда в обоих интерфейсах есть реализация этого метода по умолчанию, и нам нужно сохранить обе эти реализации не потеряв при этом полиморфизм.