Почему в Java нет множественного наследования, но разрешена реализация нескольких интерфейсов?

Java не допускает множественного наследования, но позволяет реализовать несколько интерфейсов. Почему?


person abson    schedule 25.03.2010    source источник
comment
Я отредактировал заголовок вопроса, чтобы сделать его более информативным.   -  person Bozho    schedule 25.03.2010
comment
Интересно, что в JDK 8 будут методы расширения, который позволит определить реализацию методов интерфейса. Правила определены для управления множественным наследованием поведения, но не состояния (что, как я понимаю, более проблематично.   -  person Edwin Dalorzo    schedule 31.07.2012
comment
Прежде чем вы, ребята, тратите время на ответы, которые только говорят вам, как java реализует множественное наследование ... Я предлагаю вам перейти к ответу @Prabal Srivastava, который логически дает вам то, что должно происходить внутри, чтобы не позволять классам это право ... и разрешить только интерфейсам право разрешать множественное наследование.   -  person Yo Apps    schedule 27.11.2019


Ответы (19)


Поскольку интерфейсы указывают только что делает класс, а не как он это делает.

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

person Bozho    schedule 25.03.2010
comment
Раньше я работал на C ++ и несколько раз сталкивался с той же проблемой. Недавно я прочитал о том, что у Scala есть черты, которые мне кажутся чем-то средним между C ++ и Java. - person Niels Basjes; 30.07.2010
comment
+1, полный, но краткий и последний ответ бота, не менее простой для понимания. - person Geek; 06.08.2012
comment
Таким образом, вы избегаете проблемы с алмазом: en.wikipedia.org/wiki/Diamond_problem#The_diamond_problem < / а> - person Nick Louloudakis; 13.02.2014
comment
наконец, определение я понимаю - person Ryan; 31.12.2014
comment
Это неточный ответ. Проблема не в том, чтобы указать, как и Java 8 должны доказать. В Java 8 два суперинтерфейса могут объявлять один и тот же метод с разными реализациями, но это не проблема, потому что методы интерфейса являются виртуальными, поэтому вы можете просто перезаписать их, и проблема решено. Настоящая проблема заключается в неоднозначности в атрибутах, потому что вы не можете решить эту неоднозначность, перезаписав атрибут (атрибуты не являются виртуальными). - person Alex Oliveira; 13.07.2016
comment
Что вы подразумеваете под атрибутами? - person Bozho; 22.07.2016
comment
@AlexOliveira здесь. Метод можно легко переопределить, и двусмысленность будет решена; с другой стороны, поле - это просто хранилище данных без какой-либо виртуальной таблицы диспетчеризации. Вы получите либо: дублированные поля, где каждый класс видит только свои собственные поля, либо унифицированные поля, при этом все классы наступают друг другу на пятки (и не имеют возможности переопределить это поведение). - person marcus; 03.10.2018
comment
@AlexOliveira настолько прав, а выбранный ответ настолько неверен. Deadly Diamond of Death никогда не было проблемой, когда дело касалось методов. Важно столкновение переменных. Потому что с помощью методов по умолчанию в интерфейсах у вас все еще может быть свое ромбовидное созвездие, но вы не можете столкнуться с переменными. Java 8 доказывает, что это неверно. Ответы на этот вопрос следует переустановить, и на них следует отвечать с учетом последних достижений Java. - person JayC667; 03.03.2020
comment
@marcus Спасибо, что прояснили это состояние / поля создают двусмысленность. Но почему не может та же логика реализации метода по умолчанию, используемого в Java 8 для полей ... например, при использовании множественного наследования нам также необходимо предоставить значение по умолчанию для полей, которое решило бы проблему неоднозначности для полей - person Gautam Naik; 16.01.2021
comment
@GautamNaik Значение имеет не только значение по умолчанию, но и будет ли пространство, выделенное для поля, объединяться с другими полями с тем же именем? Будет ли JVM перенаправлять все операции чтения и записи в объединенные поля? Я думаю, что это было бы возможно, но это изменило бы ментальную модель, которую имеют программисты (поля - это части памяти, методы - это действия, которые можно вызывать), и это замедлило бы некоторые операции (доступ к полю потребовал бы виртуальная рассылка). Не невозможно, но если вы посмотрите на то, что сделали C ++ и Scala, вы увидите, что он становится более сложным (виртуальные базовые классы, все поля являются методами) - person marcus; 16.01.2021
comment
@marcus Спасибо за это, я согласен, что сложность возрастет, и главный девиз Java - быть простым объектно-ориентированным языком. - person Gautam Naik; 24.01.2021

Один из моих преподавателей в колледже объяснил мне это так:

Предположим, у меня есть один класс - тостер, а другой - NuclearBomb. У них обоих может быть настройка «тьма». У них обоих есть метод on (). (У одного есть off (), у другого нет.) Если я хочу создать класс, являющийся подклассом обоих из них ... как вы можете видеть, это проблема, которая действительно может взорваться у меня здесь .

Итак, одна из основных проблем заключается в том, что если у вас есть два родительских класса, они могут иметь разные реализации одной и той же функции - или, возможно, две разные функции с одинаковым именем, как в примере с моим инструктором. Затем вам нужно решить, какой из подклассов будет использовать. Конечно, есть способы справиться с этим - это делает C ++, но разработчики Java чувствовали, что это слишком усложнит задачу.

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

person Syntactic    schedule 25.03.2010
comment
Спасибо, NomeN. Источником цитаты был аспирант по имени Брендан Бернс, который в то время также был сопровождающим репозитория исходного кода Quake 2 с открытым исходным кодом. Иди разберись. - person Syntactic; 25.03.2010
comment
Проблема с этой аналогией в том, что если вы создаете подкласс ядерной бомбы и тостера, ядерный тостер разумно взорвется при использовании. - person 101100; 27.03.2013
comment
Если кто-то решит смешать ядерную бомбу и тостер, он заслуживает, чтобы бомба взорвалась ему в лицо. Цитата является ошибочным рассуждением - person masoud; 19.05.2013
comment
Один и тот же язык программирования допускает множественное наследование интерфейсов, поэтому это обоснование неприменимо. - person curiousguy; 19.05.2013
comment
Лол только сейчас смотрю на это, но большое голосование за @masoud. Каждый студент, изучающий информатику, должен задавать этот вопрос - person Tomvkgames; 11.12.2020
comment
ИЛИ вы получите ядерный тостер. - person MC Emperor; 05.02.2021
comment
Точно так же, как мы не дошли до получения многострочных строк, а когда мы это сделали, реализация совершенно бесполезна, и из-за ее выпуска никогда не будет исправлена. Теперь у вас есть поддержка многострочных строк, но удачи во внедрении значения. Я буквально реализовал поддержку свойств и полей в интерфейсах, и можно использовать статическую хэш-карту, которая отслеживает это значение. Я посмотрю, смогу ли я выпустить его, но он имеет некоторые оговорки, например, утечки памяти, если он используется неправильно. Java должна предоставить подобную или лучшую реализацию, но я думаю, нам нужно подождать ... - person mmm; 23.04.2021

Поскольку наследование используется слишком часто, даже когда вы не можете сказать: «Эй, этот метод выглядит полезным, я также расширю этот класс».

public class MyGodClass extends AppDomainObject, HttpServlet, MouseAdapter, 
             AbstractTableModel, AbstractListModel, AbstractList, AbstractMap, ...
person Michael Borgwardt    schedule 25.03.2010
comment
Можете ли вы объяснить, почему вы говорите, что наследованием злоупотребляют? Создание класса бога - это именно то, чем я хочу заниматься! Я нахожу так много людей, которые работают с одиночным наследованием, создавая классы инструментов со статическими методами. - person Duncan Calvert; 12.08.2014
comment
@DuncanCalvert: Нет, вы не хотите этого делать, если этот код когда-нибудь будет нуждаться в обслуживании. Многие статические методы упускают из виду объектно-ориентированный подход, но чрезмерное множественное наследование намного хуже, потому что вы полностью теряете информацию о том, какой код где используется, а также о том, что концептуально представляет собой класс. Оба пытаются решить проблему того, как я могу использовать этот код там, где он мне нужен, но это простая краткосрочная проблема. Гораздо более сложная долгосрочная проблема, решаемая правильным объектно-ориентированным дизайном, заключается в том, как мне изменить этот код, чтобы программа не прерывалась в 20 разных местах непредсказуемыми способами? - person Michael Borgwardt; 12.08.2014
comment
@DuncanCalvert: и вы решаете это, имея классы с высокой связностью и низкой связью, что означает, что они содержат фрагменты данных и кода, которые интенсивно взаимодействуют друг с другом, но взаимодействуют с остальной частью программы только через небольшой простой общедоступный API. Затем вы можете думать о них с точки зрения этого API, а не внутренних деталей, что важно, потому что люди могут одновременно помнить только ограниченное количество деталей. - person Michael Borgwardt; 12.08.2014
comment
@MichaelBorgwardt, ваши рассуждения ошибочны. - person mmm; 23.04.2021
comment
@ ммм, ты можешь указать как? - person Michael Borgwardt; 23.04.2021
comment
Потому что для этого у нас уже есть интерфейсы. Простое добавление доступности свойств / полей ничего не усложнит, а наоборот упростит. Разделение реализаций на интерфейсы с помощью методов по умолчанию, например, где каждый интерфейс имеет одну зависимость, скажем, SessionFactory sessionFactory (); и реализовать всю логику, относящуюся к SessionFactory, и, скажем, другой интерфейс, реализующий дерьмо, относящееся к Session session (); будет намного чище, чем наличие SessionFactory и Session, объявленных в одном классе. Разделяя их, каждый обрабатывает свою область и .... - person mmm; 23.04.2021
comment
Для кого-то с 326K это удивительно. Я не из мира Scala, но там есть что-то под названием Traits. Ты слышал об этом? Представьте себе интерфейсы по умолчанию с состоянием. Нет причин, по которым это невозможно, потому что это можно реализовать таким же образом. Мне все равно, что государство / собственность могут быть частными, но на самом деле они могут быть общедоступными и / или защищенными. Когда мир Java проснется, мы, возможно, в конце концов получим эту функцию, но у меня мало надежд. Мы подождали до 2021 года, чтобы получить многострочные струны, и они сильно прикрутили эту часть, и вот ... - person mmm; 23.04.2021
comment
Они сделали методы по умолчанию в интерфейсах возможностью объявлять частные, что было желательно, но полностью упустили возможность защиты. Возможно, вы захотите предоставить подклассу или субинтерфейсу доступ к реализации, если они решат переопределить ваш общедоступный метод, но нет. Только личное. Фцук. По крайней мере, этот подлежит выкупу. - person mmm; 23.04.2021
comment
Также кеширование теперь невозможно из-за ограничения интерфейса, неспособного удерживать состояние. Итак, если у вас есть вычисления, которые нужно выполнить только один раз, удачи. Обратите внимание, что у меня есть код, который позволяет мне состояние в интерфейсах, но я бы не стал использовать его для большой среды, но его можно использовать для большинства других вещей. Поскольку интерфейс всегда будет содержать this, из-за того, что у кого-то есть экземпляр интерфейса, можно создать статический WeakIdentityHashMap, чтобы сопоставить его с состоянием. Это означает, что интерфейс interfae может вызывать staticmap.get (this) и объект состояния. Так что даже я могу это сделать ... - person mmm; 23.04.2021
comment
Для меня методы по умолчанию в интерфейсах - это лучшее, что есть после нарезки хлеба, и они привели к снижению общей сложности моего кода в 100 раз. Я могу просто реализовать интерфейс, чтобы внедрить любое поведение, которое я хочу, чтобы мой новый класс и / или интерфейс имел. Все, что мне нужно сделать, это реализовать один метод, чтобы предоставить что? Обычно экземпляр. Вы не можете победить это. Экземпляр все еще может потребоваться через реализацию абстрактного метода, но отсутствие возможности удерживать состояние в интерфейсах - это разница между интерфейсами и классами на этом этапе и предотвращает ... - person mmm; 23.04.2021
comment
... например, вспомогательные значения создаются на основе другого предоставленного значения, и, например, это значение должно быть кэшировано. Кеширование невозможно. Другие методы не могут использовать вашу ценность. Дело в том, что интерфейс всегда связан с этим, и поэтому нет реальной причины, почему он не может удерживать состояние, относящееся только к этому интерфейсу. Конфликты в других интерфейсах? Как это решается с помощью дублирующих методов интерфейса? Так же. Ввести некоторый синтаксис и принудительно переопределить субинтерфейсы / подклассы и разрешить доступ через SuperInteface.super.myproperty; - person mmm; 23.04.2021

Ответ на этот вопрос заключается во внутренней работе java-компилятора (цепочка конструкторов). Если мы видим внутреннюю работу java-компилятора:

public class Bank {
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank{
 public void printBankBalance(){
    System.out.println("20k");
  }
}

После компиляции это выглядит так:

public class Bank {
  public Bank(){
   super();
  }
  public void printBankBalance(){
    System.out.println("10k");
  }
}
class SBI extends Bank {
 SBI(){
   super();
 }
 public void printBankBalance(){
    System.out.println("20k");
  }
}

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

Приведенный выше код будет работать нормально. но если у нас есть другой класс с именем Car, который расширяет Bank и один гибридный (множественное наследование) класс с именем SBICar:

class Car extends Bank {
  Car() {
    super();
  }
  public void run(){
    System.out.println("99Km/h");
  }
}
class SBICar extends Bank, Car {
  SBICar() {
    super(); //NOTE: compile time ambiguity.
  }
  public void run() {
    System.out.println("99Km/h");
  }
  public void printBankBalance(){
    System.out.println("20k");
  }
}

В этом случае (SBICar) не удастся создать цепочку конструкторов (неоднозначность времени компиляции).

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

Чтобы узнать о новой концепции методов default и static, обратитесь к по умолчанию в интерфейсе .

Надеюсь, это решит ваш вопрос. Спасибо.

person Prabal Srivastava    schedule 25.03.2019

Вы можете найти точный ответ на этот запрос на странице документации Oracle о множественном наследовании

  1. Множественное наследование состояния: возможность наследовать поля от нескольких классов.

    Одна из причин, по которой язык программирования Java не позволяет вам расширять более одного класса, заключается в том, чтобы избежать проблем множественного наследования состояния, то есть возможности наследовать поля от нескольких классов.

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

    1. What if methods or constructors from different super classes instantiate the same field?
    2. Какой метод или конструктор будет иметь приоритет?
  2. Множественное наследование реализации: возможность наследовать определения методов от нескольких классов.

    Проблемы с этим подходом: конфликт имен и двусмысленность. Если подкласс и суперкласс содержат одно и то же имя метода (и подпись), компилятор не может определить, какую версию вызывать.

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

    Обратитесь к нижеприведенному сообщению SE для получения более подробной информации о решении проблемы с бриллиантами:

    В чем различия между абстрактными классами и интерфейсами в Java 8?

  3. Множественное наследование типа: способность класса реализовывать более одного интерфейса.

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

person Ravindra babu    schedule 17.09.2016

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

person Tadeusz Kopec    schedule 25.03.2010
comment
В чем проблема с алмазом смерти? - person curiousguy; 21.05.2013
comment
@curiousguy Содержит более одного подобъекта одного и того же базового класса, неоднозначность (переопределение использования базового класса), сложные правила разрешения такой неоднозначности. - person Tadeusz Kopec; 22.05.2013
comment
@curiousguy: если фреймворк предусматривает, что приведение ссылки на объект к ссылке базового типа будет сохранять идентичность, тогда каждый экземпляр объекта должен иметь ровно одну реализацию любого метода базового класса. Если ToyotaCar и HybridCar оба являются производными от Car и переопределяют Car.Drive, и если PriusCar унаследовал оба , но не переопределяет Drive, система не сможет определить, что виртуальный Car.Drive должен делать. Интерфейсы избегают этой проблемы, избегая выделенного курсивом условия выше. - person supercat; 16.06.2013
comment
@curiousguy: стоит отметить, что некоторые фреймворки избегают этой проблемы, не разрешая приведения с сохранением идентичности к базовому типу. Если в коде нельзя было использовать метод Drive или преобразовать его в Car без предварительного преобразования в HybridCar или ToyotaCar, двусмысленности можно было бы избежать, но результат последовательности преобразования _5 _- ›_ 6 _-› _ 7_ будет отличаться от результата PriusCar - ›_ 9 _-› _ 10_ (это означает, что приведение не будет сохранять идентичность). - person supercat; 16.06.2013
comment
@supercat система не сможет определить, что должен делать виртуальный Car.Drive. ‹- Или он может просто выдать ошибку компиляции и заставить вас явно выбрать одну, как это делает C ++. - person Chris Middleton; 13.08.2015
comment
@ChrisMiddleton: метод void UseCar(Car &foo); нельзя ожидать, что он будет включать устранение неоднозначности между ToyotaCar::Drive и HybridCar::Drive (поскольку он часто не должен знать и не заботиться о том, что эти другие типы даже существуют). Язык может, как и C ++, требовать, чтобы этот код ToyotaCar &myCar, желающий передать его UseCar, должен сначала привести к HybridCar или ToyotaCar, но поскольку ((Car) (HybridCar) myCar) .Drive` и ((Car)(ToyotaCar)myCar).Drive будут делать разные вещи, это будет означать, что апкасты не сохраняли идентичность. - person supercat; 13.08.2015

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

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

В официальном документе под названием «Java: обзор», написанном Джеймсом Гослингом в феврале 1995 г. (ссылка - стр. 2) дает представление о том, почему множественное наследование не поддерживается в Java.

По словам Гослинга:

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

person Praveen Kumar    schedule 28.09.2016
comment
ссылка недоступна. Пожалуйста, проверьте и обновите его. - person MashukKhan; 22.06.2020

Говорят, что состояние объектов указывается в соответствии с полями в нем, и это станет неоднозначным, если будет унаследовано слишком много классов. Вот ссылка

http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html

person Karthik GVD    schedule 13.02.2014

По той же причине C # не допускает множественного наследования, но позволяет реализовать несколько интерфейсов.

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

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

Разрешение нескольких интерфейсов позволяет вам использовать шаблоны проектирования (например, адаптер) для решения тех же типов проблем, которые вы можете решить с помощью множественного наследования, но гораздо более надежным и предсказуемым образом.

person Justin Niessner    schedule 25.03.2010
comment
В C # нет множественного наследования именно потому, что Java этого не допускает. Он был разработан намного позже Java. Я думаю, что основная проблема множественного наследования заключалась в том, как людей учили использовать его направо и налево. Идея о том, что делегирование в большинстве случаев является гораздо лучшей альтернативой, просто отсутствовала в начале и середине девяностых. Поэтому я помню примеры в учебниках, когда «Автомобиль» - это колесо, дверь и лобовое стекло, а «Автомобиль» - это колеса, двери и лобовое стекло. Таким образом, единственное наследование в Java было рефлексией на эту реальность. - person Alexander Pogrebnyak; 25.03.2010
comment
@AlexanderPogrebnyak: выберите два из следующих трех: (1) Разрешить сохранение идентичности приведения из ссылки подтипа в ссылку супертипа; (2) Разрешить классу добавлять виртуальные открытые члены без перекомпиляции производных классов; (3) Разрешить классу неявно наследовать виртуальные члены от нескольких базовых классов без необходимости их явно указывать. Я не верю, что какой-либо язык может управлять всеми тремя перечисленными выше. Java выбрала №1 и №2, а C # последовала его примеру. Я считаю, что C ++ принимает только № 3. Лично я считаю, что №1 и №2 более полезны, чем №3, но другие могут отличаться. - person supercat; 16.06.2013
comment
@supercat Я не верю, что какой-либо язык может управлять всеми тремя из вышеперечисленных - если смещения элементов данных определяются во время выполнения, а не во время компиляции (как в нехрупком ABI Objective-C), и или на основе каждого класса (т.е. каждый конкретный класс имеет свою собственную таблицу смещения членов), тогда я думаю, что все 3 цели могут быть достигнуты. - person The Paramagnetic Croissant; 27.09.2015
comment
@TheParamintageCroissant: Основная семантическая проблема - №1. Если D1 и D2 оба наследуются от B, и каждая переопределяет функцию f, и если obj является экземпляром типа S, который наследуется от D1 и D2, но не отменяет f, то приведение ссылки на S к D1 должно что-то дать f которого использует переопределение D1, и приведение к B не должно это менять. Точно так же приведение ссылки S к D2 должно привести к чему-то, f которого использует D2 переопределение, а приведение к B не должно этого изменить. Если для языка не нужно было разрешать добавление виртуальных участников ... - person supercat; 27.09.2015
comment
... без перекомпиляции он мог разрешить множественное наследование в случаях, когда не было двусмысленности и крика, если что-то стало неоднозначным, но если D1 и D2 можно изменить и перекомпилировать без перекомпиляции S, тогда могут возникнуть неоднозначности, которые не сможет сделать ни один компилятор чтобы увидеть. - person supercat; 27.09.2015
comment
@supercat Я бы сказал, что если и D1, и D2 (или даже один из них) переопределяют f, то S также должен переопределить его, иначе это ошибка компилятора (поскольку при вызове f объекта объявленного типа S, как можно решить звонить ли D1::f или D2::f?) - person The Paramagnetic Croissant; 27.09.2015
comment
@TheParamintageCroissant: если S компилируется в то время, когда ни D1, ни D2 не переопределяют f, но оба класса будут изменены в будущем, чтобы переопределить его, на каком этапе компиляции должен произойти крик? Компиляция S не может кричать, потому что не знает, что D1 и D2 изменятся. Сборники D1 и D2 не могут кричать, так как ничего не знают о S. - person supercat; 27.09.2015
comment
@supercat Правильно ... разве нельзя проверить эту ситуацию во время выполнения? - person The Paramagnetic Croissant; 27.09.2015
comment
@TheParamintageCroissant: Может, и мой список вариантов был несколько упрощен, чтобы уместиться в комментарии, но откладывание на время выполнения не позволяет автору D1, D2 или S знать, какие изменения они могут внести, не нарушая потребители своего класса. - person supercat; 27.09.2015
comment
@supercat да, это серьезная проблема. - person The Paramagnetic Croissant; 27.09.2015

Поскольку эта тема не закрыта, я отправлю этот ответ, надеюсь, это поможет кому-то понять, почему java не допускает множественное наследование.

Рассмотрим следующий класс:

public class Abc{

    public void doSomething(){

    }

}

В этом случае класс Abc ничего не расширяет, верно? Не так быстро, этот класс неявно расширяет класс Object, базовый класс, который позволяет всему работать в java. Все есть объект.

Если вы попытаетесь использовать приведенный выше класс, вы увидите, что ваша IDE позволяет использовать такие методы, как: equals(Object o), toString() и т. Д., Но вы не объявляли эти методы, они пришли из базового класса Object

Вы можете попробовать:

public class Abc extends String{

    public void doSomething(){

    }

}

Это нормально, потому что ваш класс не будет неявно расширять Object, но будет расширять String, потому что вы это сказали. Рассмотрим следующее изменение:

public class Abc{

    public void doSomething(){

    }

    @Override
    public String toString(){
        return "hello";
    }

}

Теперь ваш класс всегда будет возвращать «привет», если вы вызываете toString ().

А теперь представьте себе следующий класс:

public class Flyer{

    public void makeFly(){

    }

}

public class Bird extends Abc, Flyer{

    public void doAnotherThing(){

    }

}

Снова класс Flyer неявно расширяет объект, который имеет метод toString(), любой класс будет иметь этот метод, поскольку все они расширяют Object косвенно, поэтому, если вы вызовете toString() из Bird, какую toString() java должна будет использовать? С Abc или Flyer? Это произойдет с любым классом, который пытается расширить два или более классов, чтобы избежать такого «столкновения методов», они построили идею интерфейса, в основном вы могли бы думать их как абстрактный класс который не расширяет Object косвенно. Поскольку они абстрактны, они должны быть реализованы классом, который является объектом (вы не можете создать экземпляр интерфейса в одиночку, они должны быть реализованы классом), поэтому все будет работать нормально.

Чтобы отличать классы от интерфейсов, ключевое слово реализует только для интерфейсов.

Вы можете реализовать любой интерфейс, который вам нравится, в том же классе, поскольку они по умолчанию ничего не расширяют (но вы можете создать интерфейс, который расширяет другой интерфейс, но, опять же, «родительский» интерфейс не расширяет Object »), поэтому интерфейс просто интерфейс, и они не будут страдать от "коллизий сигнатур методов", если они это сделают, компилятор выдаст вам предупреждение, и вам просто нужно будет изменить сигнатуру метода, чтобы исправить это (подпись = метод имя + параметры + возвращаемый тип).

public interface Flyer{

    public void makeFly(); // <- method without implementation

}

public class Bird extends Abc implements Flyer{

    public void doAnotherThing(){

    }

    @Override
    public void makeFly(){ // <- implementation of Flyer interface

    }

    // Flyer does not have toString() method or any method from class Object, 
    // no method signature collision will happen here

}
person Murillo Ferreira    schedule 11.06.2016

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

  1. В java каждый класс является дочерним по отношению к классу Object. Когда он наследуется от более чем одного суперкласса, подкласс получает неоднозначность, чтобы получить свойство класса Object.
  2. В java у каждого класса есть конструктор, напишем мы его явно или не напишем вообще. Первый оператор вызывает super() для вызова конструктора класса ужина. Если у класса более одного суперкласса, он запутается.

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

person raghu.g.b Raghu    schedule 27.07.2019

Потому что интерфейс - это просто контракт. А класс на самом деле является контейнером для данных.

person Snake    schedule 25.03.2010
comment
Основная трудность с множественным наследованием заключается в возможности того, что класс может наследовать член по множеству путей, которые реализуют его по-разному, без предоставления собственной переопределяющей реализации. Наследование интерфейса позволяет избежать этого, поскольку единственное место, где могут быть реализованы члены интерфейса, - это классы, потомки которых будут ограничены одиночным наследованием. - person supercat; 16.06.2013

Например, два класса A, B имеют один и тот же метод m1 (). А класс C расширяет как A, так и B.

 class C extends A, B // for explaining purpose.

Теперь класс C будет искать определение m1. Сначала он будет искать в классе, если не нашел, затем проверит класс родителей. Оба A и B имеют определение. Итак, здесь возникает двусмысленность, какое определение следует выбрать. Таким образом, JAVA НЕ ПОДДЕРЖИВАЕТ МНОЖЕСТВЕННОЕ НАСЛЕДОВАНИЕ.

person Pooja Khatri    schedule 13.05.2018
comment
как насчет того, чтобы компилятор java давал компилятору, если те же методы или переменные определены в обоих родительских классах, чтобы мы могли изменить код ... - person siluveru kiran kumar; 09.08.2019

Все мы знаем, что мы можем наследовать (расширять) один класс, но мы можем реализовать так много интерфейсов ... это потому, что в интерфейсах мы не даем реализации, просто говорим о функциональности. предположим, если java может расширять так много классов и у них одинаковые методы ... в этом месте, если мы попытаемся вызвать метод суперкласса в подклассе, какой метод предполагается запустить ??, компилятор запутается пример: - попробуйте несколько расширений, но в интерфейсах эти методы не имеют тел, которые мы должны реализовать в подклассе .. попробуйте использовать несколько орудий, так что не беспокойтесь ..

person hasanga lakdinu    schedule 19.09.2019

Возьмем, к примеру, случай, когда класс A имеет метод getSomething, а класс B имеет метод getSomething, а класс C расширяет A и B. Что произойдет, если кто-то вызовет C.getSomething? Невозможно определить, какой метод вызывать.

Интерфейсы в основном просто указывают, какие методы должен содержать реализующий класс. Класс, реализующий несколько интерфейсов, просто означает, что класс должен реализовать методы из всех этих интерфейсов. Whci не приведет к каким-либо проблемам, описанным выше.

person John Kane    schedule 25.03.2010
comment
Что произойдет, если кто-то вызовет C.getSomething. Это ошибка C ++. Задача решена. - person curiousguy; 19.05.2013
comment
В том-то и дело ... это был контрпример, который я считал ясным. Я указывал на то, что нет способа определить, какой метод get something следует вызвать. Также в качестве побочного примечания вопрос был связан с java, а не с ++ - person John Kane; 20.05.2013
comment
Мне жаль, что я не понимаю, о чем вы говорите. Очевидно, что в некоторых случаях с ИМ есть двусмысленность. Как это контрпример? Кто утверждал, что МИ никогда не приводят к двусмысленности? Также в качестве примечания, вопрос был связан с java, а не c ++ Итак? - person curiousguy; 21.05.2013
comment
Я просто пытался показать, почему существует эта двусмысленность и почему она не связана с интерфейсами. - person John Kane; 21.05.2013
comment
Да, MI может приводить к неоднозначным вызовам. Так что может перегрузка. Значит, Java должна убрать перегрузку? - person curiousguy; 21.05.2013
comment
...нет. Если класс расширяет несколько классов, и оба суперкласса расширяют один и тот же метод, это приведет к ошибкам. Невозможно определить правильный метод для вызова. Перегрузка работает, потому что это недопустимо. Я не уверен, почему перегрузка приведет к неоднозначному вызову, то, что вызывается, определяется областью действия. - person John Kane; 21.05.2013
comment
Разрешение перегрузки иногда приводит к неоднозначности в C ++ или Java. - person curiousguy; 21.05.2013
comment
Я имел в виду только java (язык, о котором был задан вопрос). Вы можете привести пример того, как перегрузка может быть неоднозначной в Java? Я не могу вспомнить ни одного случая рук. - person John Kane; 21.05.2013
comment
позвольте нам продолжить обсуждение в чате - person curiousguy; 21.05.2013
comment
@curiousguy: множественное наследование может не быть проблемой, если добавление виртуальных общедоступных членов к базовому классу потребует перекомпиляции всех производных классов, и / или один не нуждается в сохраняющих идентичность приведениях типов из подтипа в его базовый тип. Однако и Java, и .NET предоставляют обе эти функции; это, в свою очередь, требует, чтобы классы явно указывали реализацию всех виртуальных членов, которые могут быть импортированы из более чем одного источника [что и делают обе структуры, требуя, чтобы такие члены импортировались через интерфейсы]. - person supercat; 16.06.2013

Рассмотрим сценарий, в котором Test1, Test2 и Test3 - это три класса. Класс Test3 наследует классы Test2 и Test1. Если классы Test1 и Test2 имеют один и тот же метод, и вы вызываете его из объекта дочернего класса, будет неоднозначность для вызова метода класса Test1 или Test2, но для интерфейса нет такой неоднозначности, поскольку в интерфейсе нет реализации.

person Nikhil Kumar    schedule 21.04.2015

Java не поддерживает множественное наследование, многопутевое и гибридное наследование из-за проблемы неоднозначности:

 Scenario for multiple inheritance: Let us take class A , class B , class C. class A has alphabet(); method , class B has also alphabet(); method. Now class C extends A, B and we are creating object to the subclass i.e., class C , so  C ob = new C(); Then if you want call those methods ob.alphabet(); which class method takes ? is class A method or class B method ?  So in the JVM level ambiguity problem occurred. Thus Java does not support multiple inheritance.

множественное наследование

Ссылка для справки: https://plus.google.com/u/0/communities/102217496457095083679

person Community    schedule 23.01.2017

* Это простой ответ, поскольку я новичок в Java *

Представьте, что существует три класса _1 _, _ 2_ и Z.

Таким образом, мы наследуем как X extends Y, Z И как Y, так и Z имеют метод alphabet() с тем же типом возвращаемого значения и аргументами. Этот метод alphabet() в Y указывает отображать первый алфавит, а алфавит метода в Z говорит отображать последний алфавит. Таким образом, возникает двусмысленность, когда alphabet() вызывается X. Говорит ли он отображать первый или последний алфавит ??? Итак, java не поддерживает множественное наследование. В случае интерфейсов считайте Y и Z интерфейсами. Таким образом, оба будут содержать объявление метода alphabet(), но не определение. Он не скажет, отображать ли первый алфавит или последний алфавит или что-то еще, а просто объявит метод alphabet(). Так что нет причин вызывать двусмысленность. Мы можем определить метод с чем угодно внутри класса X.

Одним словом, определение интерфейсов выполняется после реализации, поэтому нет путаницы.

person AJavaLover    schedule 05.01.2018

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

person hema    schedule 19.06.2021
comment
Есть более конкретные ответы. Я думаю конкретно о проблеме алмаза C ++ - person ahoffer; 20.06.2021