Java не допускает множественное наследование, но позволяет реализовать несколько интерфейсов. Зачем?
153
Java не допускает множественное наследование, но позволяет реализовать несколько интерфейсов. Зачем?
Ответы:
Поскольку интерфейсы определяют только то, что делает класс, а не как он это делает.
Проблема множественного наследования заключается в том, что два класса могут определять разные способы выполнения одной и той же вещи, и подкласс не может выбирать, какой из них выбрать.
источник
Один из преподавателей моего колледжа объяснил мне это так:
Таким образом, одна из основных проблем заключается в том, что если у вас есть два родительских класса, они могут иметь разные реализации одной и той же функции или, возможно, две разные функции с одинаковым именем, как в примере моего инструктора. Затем вы должны решить, какой из ваших подклассов использовать. Конечно, есть способы справиться с этим - C ++ делает это - но разработчики Java чувствовали, что это усложнит ситуацию.
Тем не менее, с помощью интерфейса вы описываете то, на что способен класс, а не заимствуете метод другого класса. Несколько интерфейсов с гораздо меньшей вероятностью могут вызвать сложные конфликты, которые необходимо разрешить, чем несколько родительских классов.
источник
Поскольку наследование используется слишком часто, даже если вы не можете сказать «эй, этот метод выглядит полезным, я также расширю этот класс».
источник
Ответ на этот вопрос заключается во внутренней работе компилятора Java (цепочки конструктора). Если мы видим внутреннюю работу компилятора Java:
После компиляции это выглядит так:
когда мы расширяем класс и создаем его объект, одна цепочка конструктора будет работать до
Object
класса.Выше код будет работать нормально. но если у нас есть другой класс с именем
Car
расширяемыйBank
и один гибридный (множественное наследование) класс с именемSBICar
:В этом случае (SBICar) не удастся создать цепочку конструктора ( неоднозначность времени компиляции ).
Для интерфейсов это разрешено, потому что мы не можем создать его объект.
За новой концепцией
default
иstatic
методом обращайтесь по умолчанию в интерфейс .Надеюсь, что это решит ваш запрос. Спасибо.
источник
Реализация нескольких интерфейсов очень полезна и не доставляет особых проблем ни языковым, ни программистам. Так что это разрешено. Многократное наследование, хотя и полезно, может вызвать серьезные проблемы для пользователей (страшный алмаз смерти ). И большинство вещей, которые вы делаете с множественным наследованием, также может быть выполнено с помощью композиции или с использованием внутренних классов. Поэтому множественное наследование запрещено, поскольку оно приносит больше проблем, чем выгод.
источник
ToyotaCar
иHybridCar
оба полученыCar
и переопределеныCar.Drive
, и еслиPriusCar
унаследованы оба, но не переопределеныDrive
, система не сможет определить, чтоCar.Drive
должен делать виртуал. Интерфейсы избегают этой проблемы, избегая выделенного курсивом условия выше.void UseCar(Car &foo)
; Нельзя ожидать, что они будут содержать неоднозначность междуToyotaCar::Drive
иHybridCar::Drive
(поскольку часто не нужно ни знать, ни заботиться о том, чтобы эти другие типы вообще существовали ). Язык может, как это делает C ++, требовать, чтобы код сToyotaCar &myCar
желанием передать егоUseCar
должен сначала привести к либо,HybridCar
либоToyotaCar
, но, поскольку ((Car) (HybridCar) myCar) .Drive` и((Car)(ToyotaCar)myCar).Drive
будет делать разные вещи, это будет означать, что upcasts не были сохранением идентичности.Вы можете найти точный ответ на этот запрос на странице документации оракула о множественном наследовании.
Множественное наследование состояний: возможность наследовать поля от нескольких классов
Если допускается множественное наследование, и когда вы создаете объект путем создания экземпляра этого класса, этот объект будет наследовать поля от всех суперклассов класса. Это вызовет две проблемы.
Множественное наследование реализации: Возможность наследовать определения методов от нескольких классов.
Проблемы с этим подходом: конфликтует имя и неопределенность . Если подкласс и суперкласс содержат одно и то же имя метода (и сигнатуру), компилятор не может определить, какую версию вызывать.
Но java поддерживает этот тип множественного наследования с методами по умолчанию , которые были введены после выпуска Java 8. Компилятор Java предоставляет некоторые правила, чтобы определить, какой метод по умолчанию использует конкретный класс.
Для получения более подробной информации о решении проблемы алмазов см. Ниже.
Каковы различия между абстрактными классами и интерфейсами в Java 8?
Множественное наследование типа: способность класса реализовать более одного интерфейса.
Поскольку интерфейс не содержит изменяемых полей, вам не нужно беспокоиться о проблемах, которые возникают в результате множественного наследования состояний.
источник
Говорят, что состояние объектов указывается относительно полей в нем, и оно стало бы неоднозначным, если бы слишком много классов было унаследовано. Вот ссылка
http://docs.oracle.com/javase/tutorial/java/IandI/multipleinheritance.html
источник
Java поддерживает множественное наследование только через интерфейсы. Класс может реализовывать любое количество интерфейсов, но может расширять только один класс.
Многократное наследование не поддерживается, потому что это приводит к смертельной проблеме с алмазом. Тем не менее, это может быть решено, но это приводит к сложной системе, поэтому множественное наследование было отброшено основателями Java.
В официальном документе Джеймса Гослинга под названием «Java: обзор», опубликованном в феврале 1995 года ( ссылка ), дается представление о том, почему множественное наследование не поддерживается в Java.
По словам Гослинга:
источник
По той же причине C # не допускает множественного наследования, но позволяет реализовать несколько интерфейсов.
Урок, извлеченный из C ++ с множественным наследованием, заключался в том, что это привело к большему количеству проблем, чем оно того стоило.
Интерфейс - это контракт вещей, которые должен реализовать ваш класс. Вы не получаете никакой функциональности от интерфейса. Наследование позволяет вам наследовать функциональность родительского класса (и в случае множественного наследования это может привести к путанице).
Разрешение нескольких интерфейсов позволяет использовать шаблоны проектирования (например, адаптер) для решения тех же типов проблем, которые можно решить с помощью множественного наследования, но гораздо более надежным и предсказуемым образом.
источник
D1
иD2
как наследовать отB
, и каждый переопределяет функциюf
, и еслиobj
это экземпляр типа ,S
который наследует от обоихD1
и ,D2
но не отменяетf
, а затем отливки ссылку на ,S
чтобыD1
должно дать что - то , чьеf
используетD1
Override и отливку , чтобыB
не должен изменить это. Аналогично, приведение ссылкиS
наD2
должно привести к тому, чтоf
используетD2
переопределение, а приведение кB
не должно это изменить. Если языку не нужно разрешать добавление виртуальных членов ...Поскольку эта тема не близка, я опубликую этот ответ, я надеюсь, что это поможет кому-то понять, почему java не допускает множественное наследование.
Рассмотрим следующий класс:
В этом случае класс Abc не расширяет ничего, верно? Не так быстро, этот класс неявно расширяет класс Object, базовый класс, который позволяет всем работать в Java. Все является объектом.
Если вы пытаетесь использовать класс выше , вы увидите , что ваш IDE позволяет использовать такие методы , как:
equals(Object o)
,toString()
и т.д., но вы не объявите эти методы, они пришли из базового классаObject
Вы можете попробовать:
Это нормально, потому что ваш класс не будет неявно расширяться,
Object
но будет расширяться,String
потому что вы это сказали. Рассмотрим следующее изменение:Теперь ваш класс всегда будет возвращать «привет», если вы вызываете toString ().
Теперь представьте следующий класс:
Опять же, класс
Flyer
неявного extends Object, у которого есть методtoString()
, любой класс будет иметь этот метод, поскольку все они расширяютсяObject
косвенно, поэтому, если вы вызываетеtoString()
изBird
, какуюtoString()
java придется использовать? ОтAbc
илиFlyer
? Это произойдет с любым классом, который пытается расширить два или более классов, чтобы избежать такого «коллизии методов», в котором они построили идею интерфейса , в основном вы можете считать их абстрактным классом, который не расширяет Object косвенно . Поскольку они являются абстрактными, они должны быть реализованы классом, который является объектом (вы не можете создать интерфейс самостоятельно, он должен быть реализован классом), поэтому все будет работать нормально.Чтобы отличать классы от интерфейсов, ключевое слово Implements было зарезервировано только для интерфейсов.
Вы можете реализовать любой интерфейс, который вам нравится, в одном и том же классе, поскольку по умолчанию он ничего не расширяет (но вы можете создать интерфейс, расширяющий другой интерфейс, но, опять же, интерфейс «папа» не будет расширять объект »), поэтому интерфейс просто интерфейс, и они не пострадают от « коллизий сигнатур методов », если они это сделают, компилятор выдаст вам предупреждение, и вам просто нужно изменить сигнатуру метода, чтобы исправить ее (сигнатура = имя метода + параметры + тип возврата) ,
источник
Потому что интерфейс - это просто контракт. А класс на самом деле является контейнером для данных.
источник
Например, два класса A, B, имеющие один и тот же метод m1 (). И класс C расширяет как A, B.
Теперь класс C будет искать определение m1. Во-первых, он будет искать в классе, если он не нашел, тогда он будет проверять в классе родителей. Оба A, B имеют определение. Итак, здесь возникает неопределенность, какое определение следует выбрать. Так что JAVA НЕ ПОДДЕРЖИВАЕТ МНОГОКРАТНОЕ НАСЛЕДОВАНИЕ.
источник
Java не поддерживает множественное наследование по двум причинам:
Object
класса. Когда он наследует от более чем одного суперкласса, подкласс получает неоднозначность для приобретения свойства класса Object.super()
для вызова конструктора класса ужин. Если в классе более одного суперкласса, он запутывается.Поэтому, когда один класс расширяется из нескольких суперклассов, мы получаем ошибку времени компиляции.
источник
Возьмем, к примеру, случай, когда у класса A есть метод getSomething, а у класса B - метод getSomething, а класс C расширяет A и B. Что бы произошло, если бы кто-то вызвал C.getSomething? Нет способа определить, какой метод вызывать.
Интерфейсы в основном просто указывают, какие методы должен содержать реализующий класс. Класс, который реализует несколько интерфейсов, просто означает, что класс должен реализовывать методы из всех этих интерфейсов. Это не приведет к каким-либо проблемам, описанным выше.
источник
Рассмотрим сценарий, в котором Test1, Test2 и Test3 представляют собой три класса. Класс Test3 наследует классы Test2 и Test1. Если классы Test1 и Test2 имеют один и тот же метод, и вы вызываете его из дочернего объекта класса, будет неоднозначность для вызова метода класса Test1 или Test2, но нет такой неоднозначности для интерфейса, поскольку в интерфейсе нет реализации.
источник
Java не поддерживает множественное наследование, многолучевое и гибридное наследование из-за проблемы неоднозначности:
множественное наследование
источник
простым способом, который мы все знаем, мы можем наследовать (расширять) один класс, но мы можем реализовать так много интерфейсов, потому что в интерфейсах мы не даем реализацию, просто скажем функциональность. Предположим, что если Java может расширять так много классов и у них одни и те же методы. В этом случае, если мы попытаемся вызвать метод суперкласса в подклассе, какой метод предполагается запустить ??, компилятор запутается в примере: - попытаться использовать несколько расширений, но в интерфейсы, в которых эти методы не имеют тел, мы должны реализовать их в подклассе .. попробуйте несколько реализаций, так что не беспокойтесь ..
источник
* Это простой ответ, так как я новичок в Java *
Считайте, что есть три класса
X
,Y
иZ
.Таким образом, мы наследуем как
X extends Y, Z
And, такY
и имеемZ
методalphabet()
с тем же типом возврата и аргументами. Этот методalphabet()
вY
говорит отобразить первый алфавит и метод алфавитZ
говорит отображение последнего алфавит . Так что тут возникает двусмысленность, когдаalphabet()
вызываетсяX
. Говорит ли он отображать первый или последний алфавит ??? Так что Java не поддерживает множественное наследование. В случае интерфейсов, рассмотримY
иZ
как интерфейсы. Таким образом, оба будут содержать объявление методаalphabet()
но не определение. Он не скажет, отображать ли первый или последний алфавит или что-то еще, но просто объявит методalphabet()
, Так что нет причин поднимать эту двусмысленность. Мы можем определить метод с чем угодно внутри классаX
.Таким образом, одним словом, в Интерфейсах определение делается после реализации, поэтому нет путаницы.
источник