Множественное наследование java как сделать

Добавил пользователь Евгений Кузнецов
Обновлено: 04.10.2024

Я читаю "учебник Java" (во второй раз). Я только что прошел раздел об интерфейсах (снова), но до сих пор не понимаю, как интерфейсы Java имитируют множественное наследование. Есть ли более ясное объяснение, чем в книге?

Предположим, у вас есть 2 вида вещей в вашем домене : грузовики и кухни

тележки имеют метод driveTo() и кухни метод повара ().

теперь предположим, что Паули решает продать пиццу из задней части грузовика. Он хочет вещь, с которой он может ездить() и готовить ().

В C++ он будет использовать множественное наследование для этого.

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

таким образом, в Java мы склонны реализовывать множественное наследование, используя делегации:

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

он счастливый человек, потому что теперь он может делать такие вещи, как ;

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

(обновление: с приходом интерфейсы методов по умолчанию теперь также может обеспечить некоторое поведение, которое будет унаследовано)

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

интерфейсы позволяют множественное наследование типы, например a class Waterfowl extends Bird implements Swimmer может использоваться другими классами, как если бы это было Bird и как Swimmer . Это более глубокий смысл несколько наследование: позволяет одному объекту действовать так, как будто он принадлежит сразу нескольким несвязанным разным классам.

вот способ достижения множественного наследования через интерфейсы в java.

чего достичь?
класс A расширяет B, C / / это невозможно в java напрямую, но может быть достигнуто косвенно.

учитывая два интерфейса ниже.

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

мы не можем расширить два объекта, но мы можем реализовать два интерфейса.

интерфейсы не имитируют множественное наследование. Создатели Java считали множественное наследование неправильным, поэтому в Java нет такой вещи.

если вы хотите объединить функциональность двух классов в один - используйте композицию объекта. Т. е.

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

здесь могут пригодиться интерфейсы-if Component1 реализует интерфейс Interface1 и Component2 осуществляет Interface2 , можно определить

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

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

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

Итак, почему вы хотите их использовать? Большую часть времени ты бы не стал. Вы, конечно, не хотели бы использовать их все время, как многие, кажется, думают. Но прежде чем я дойду до того, когда ты это сделаешь, давай поговорим о том, чем они не являются.

интерфейсы не являются:

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

Они действительно так просто, как вы думаете, что они на первый взгляд. Люди злоупотребляют глупо все время, поэтому трудно понять, что точка. Это просто проверка / тестирование. После того, как вы написали что-то соответствует интерфейсу и работает, удаление этого "реализует" код ничего не сломает.

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

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

Итак, любой интерфейс, скорее всего, никогда не будет реализован более одного раза? Совершенно бесполезный. Множественное наследование? Прекрати тянуться к радуге. Java избегает их по какой-то причине в первую очередь, и составные/агрегатные объекты во многих отношениях более гибкие. Это не значит, что интерфейсы не могут помочь вы моделируете так, как позволяет множественное наследование, но это действительно не наследование в какой-либо форме или форме и не должно рассматриваться как таковое. Это просто гарантирует, что ваш код не будет работать, пока вы не реализуете все методы, которые вы установили.

Это довольно просто. В типе можно реализовать несколько интерфейсов. Так, например, у вас может быть реализация List Это также экземпляр Deque (и Java делает. LinkedList ).

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

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

Это будет работать, и вы можете использовать mfi и msi, это похоже на множественное наследование, но это не потому, что вы ничего не наследуете, вы просто переписываете общедоступные методы, предоставляемые межфазные границы.

вам нужно быть точным:

Java допускает множественное наследование интерфейса, но только одно наследование реализации.

вы делаете множественное наследование интерфейса в Java следующим образом:

кстати, причина, по которой Java не реализует полное множественное наследование, заключается в том, что он создает двусмысленности. Предположим, вы можете сказать "a расширяет B, C", а затем и B, и C имеют функцию "void f(int)". Какая реализация наследуется? С подходом Java вы можете реализовать любое количество интерфейсов, но интерфейсы только объявляют подпись. Поэтому, если два интерфейса включают функции с одной и той же сигнатурой, отлично, ваш класс должен реализовать функцию с этой сигнатурой. Если интерфейсы можно наследовать функции с разными сигнатурами, то функции не имеют ничего общего друг с другом, поэтому нет и речи о конфликте.

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

несправедливо говорить, что интерфейсы "имитируют" множественное наследование.

конечно, ваш тип может реализовать несколько интерфейсов и действовать как много разных типов полиморфно. Однако вы, очевидно, не унаследуете поведение или реализации в соответствии с этим соглашением.

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

Я думаю, что путаница исходит от людей, полагающих, что реализация интерфейса представляет собой некоторую форму наследования. Это не так; реализация может быть просто пустой, никакое поведение не навязывается актом или не гарантируется каким-либо контрактом. Типичным примером является clonable-интерфейс, который, намекая на множество отличных функций, определяет так мало, что это по существу бесполезно и потенциально опасно.

Что вы наследовать путем реализации интерфейса? Шиш! Поэтому, на мой взгляд, прекратите использовать слова interface и inheritance в одном предложении. Как сказал Майкл Боргвардт, интерфейс-это не определение, а аспект.

вы можете фактически "наследовать" от нескольких конкретных классов, если они реализуют интерфейсы сами. innerclasses помочь вам достичь этого:

Я не думаю, что они делают.

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

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

в Java действительно нет моделирования множественного наследования.

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

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

есть случаи, когда множественное наследование оказывается очень удобным и трудным для замены интерфейсами без написания большего количества кода. Например, есть Android-приложения, которые используют классы, производные от Activity и другие от FragmentActivity в том же приложении. Если у вас есть определенная функция, которую вы хотите поделиться в общем классе, в Java вам придется дублировать код, а не позволять дочерним классам Activity и FragmentsActivity выводиться из того же класса SharedFeature. И бедные реализация дженериков в Java также не помогает, потому что написание следующего является незаконным:

в java нет поддержки множественного наследования.

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

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

Я хотел бы указать на то, что укусило меня сзади, исходя из C++, где вы можете легко наследовать много реализаций.

наличие "широкого" интерфейса со многими методами означает, что вам придется реализовать множество методов в ваших конкретных классах и вы не можете поделиться этим легко в разных реализациях.

в этом примере Fox и Bear не могут совместно использовать общую базовую реализацию для оба это методы интерфейса munch и devour .

если базовые реализации выглядят так, мы, возможно, захотим использовать их для Fox и Bear :

но мы не можем унаследовать оба. Базовые реализации должны быть переменными-членами в классе, и определенные методы могут перенаправлять их. Т. е.:

это становится громоздким, если интерфейсы растут (т. е. более 5-10 методов. )

лучший подход-определить интерфейс как агрегация интерфейсов:

это означает, что Fox и Bear только должен реализовать эти два метода, а интерфейсы и базовые классы могут расти независимо от агрегата AllEater интерфейс, который касается реализации классов.

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

Я также должен сказать, что Java не поддерживает множественное наследование.

вы должны различать значение между extends и implements ключевые слова в Java. Если мы используем extends , мы фактически наследуем класс после этого ключевого слова. Но, чтобы сделать все просто, мы не можем использовать extends более одного раза. Но вы можете реализовать столько интерфейсов, сколько вы хотите.

если вы реализуете интерфейс, есть нулевой шанс, что вы пропустите реализация всех методов в каждом интерфейсе (исключение: реализация по умолчанию методов интерфейса, введенных в Java 8) Итак, теперь вы полностью осведомлены о том, что происходит с вещами, которые вы внедрили в свой новый класс.

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

Внутренний класс связан с экземпляром его обрамляющего класса (из документации).

Пример внутреннего класса есть в документации.


Так в чем же отличие, спросите вы. Объявления классов и вложенных и внутренних
одинаковые в данных случаях. Отличие в том, что внутренний класс связан с внешним классом через экземпляр, или через объект класса.

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

По-другому мы можем написать так:


Обратите внимание на запись вида myOuter = Outer5.this; . Она означает получение ссылки на текущий экземпляр внешнего класса Outer5.this.

Рассмотрим свойства внутренних классов.

Внутренние классы есть смысл использовать, если они будут использовать элементы родителя,
чтобы не передавать лишнего в конструкторах. Внутренний класс неявно наследуется от внешнего класса, хотя мы не используем ключевое слово extends в случае с классом или implements в случае с интерфейсом. То есть, во внутреннем классе мы можем использовать весь унаследованный функционал внешнего класса. Может показаться, что это сомнительно. Но это дает нам более гибкий подход. Таким образом мы можем использовать во внутреннем классе, функционал унаследованный от внешнего класса.

Например, Map.Entry — нигде кроме интерфейса Map и его реализаций он не используется. Смотрите исходный код Map.Entry и Map. Это я привел только один пример.

Далее рассмотрим пример явного наследования.


В этом примере у нас, по сути, получилось множественное наследование, и мы можем использовать функционал класса AnyClass и функционал класса Outer6.



рис. 1



«Каждый внутренний класс может независимо наследовать определенную реализацию.

Объект внутреннего класса сохраняет информацию о месте, где он был создан.

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

Наследование представляет собой отношение IS-A, которое также известно как отношение родитель-ребенок.

Наследование в программировании на Java может быть определено как процесс, в котором один класс приобретает свойства (методы и поля) другого. С использованием наследования информация становится управляемой в иерархическом порядке.

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

extends – это ключевое слово, используемое для обозначения наследования свойств класса.

Это важная часть ООП (объектно-ориентированного программирования).

Синтаксис наследования на Java

Пример наследования, здесь есть два класса, а именно: Calculation и My_Calculation.

Используя ключевое слово extends, My_Calculation наследует методы addition() и Subtraction() класса Calculation.

Скопируйте и вставьте следующую программу в файл с именем My_Calculation.java

Скомпилируйте и выполните приведенный выше код, как показано ниже.

После выполнения программы она даст следующий результат –
The sum of the given numbers:30
The difference between the given numbers:10
The product of the given numbers:200

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

наследование Java

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

Теперь создадим экземпляр класса, как указано ниже. Но используя ссылочную переменную суперкласса (в данном случае cal), вы не можете вызвать метод multiplication(), который принадлежит подклассу My_Calculation.

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

Ключевое слово super

Ниже приведены сценарии, в которых используется ключевое слово super.

Оно используется для различения членов суперкласса от членов подкласса, если они имеют одинаковые имена. И используется для вызова конструктора суперкласса из подкласса.

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

программа, которая демонстрирует использование ключевого слова super. У вас есть два класса, а именно Sub_class и Super_class, оба имеют метод display() с разными реализациями и переменную с именем num с разными значениями.

Мы вызываем метод display() обоих классов и печатаем значение переменной num обоих классов. Здесь вы можете заметить, что мы использовали ключевое слово super, чтобы отличать членов суперкласса от подкласса.

Скопируйте и вставьте программу в файл с именем Sub_class.java.

Скомпилируйте и выполните приведенный выше код, используя следующий синтаксис.

Результат
This is the display method of subclass
This is the display method of superclass
value of the variable named num in sub class:10
value of the variable named num in super class:20

Вызов конструктора суперкласса

Если класс наследует свойства другого класса, подкласс автоматически получает конструктор по умолчанию суперкласса. Но если вы хотите вызвать параметризованный конструктор суперкласса, вам нужно использовать ключевое слово super.
super(values);

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

Скопируйте и вставьте следующую программу в файл с именем Subclass.java

Скомпилируйте и выполните приведенный выше код, используя следующий синтаксис.

Результат
The value of the variable named age in super class is: 24

IS-A отношения

IS-A – это способ показать: этот объект является типом этого объекта. Давайте посмотрим, как ключевое слово extends используется для наследования.

Теперь, на основе приведенного выше примера, в объектно-ориентированных терминах верно следующее:

  • Животное – суперкласс класса млекопитающих.
  • Животное – суперкласс рептилий.
  • Млекопитающее и Рептилия являются подклассами класса животных.
  • Собака является подклассом классов млекопитающих и животных.

Теперь, если мы рассмотрим отношения IS-A, мы можем сказать –

  • Млекопитающее IS-A животное
  • Рептилия IS-A животное
  • Собака IS-A млекопитающее
  • Отсюда: собака тоже животное

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

Мы можем гарантировать, что млекопитающее на самом деле является животным с использованием оператора экземпляра.

И результат
true
true
true

Покажем как ключевое слово Implements используется для получения отношения IS-A.

Обычно ключевое слово Implements используется с классами для наследования свойств интерфейса. Интерфейсы никогда не могут быть расширены классом.

Что такое ключевое слово instanceof в Java?

Оператор java instanceof используется для проверки того, является ли объект экземпляром указанного типа (класс, подкласс или интерфейс).

Instanceof также известен как оператор сравнения типов, потому что он сравнивает экземпляр с типом. Возвращает либо true, либо false. Если мы применяем оператор instanceof к любой переменной, которая имеет нулевое значение, она возвращает false.

Если мы применяем оператор instanceof к переменной с нулевым значением, он возвращает false.

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

Результат будет получен:
true
true
true

HAS-A отношения

HAS-A определяет, есть ли у определенного класса определенная вещь. Это соотношение помогает уменьшить дублирование кода и ошибок.

Это показывает, что класс Van имеет Speed(скорость). Имея отдельный класс скорости, нам не нужно помещать весь код, принадлежащий скорости, в класс Van, что позволяет повторно использовать класс скорости в нескольких приложениях.

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

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

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

Существуют различные типы наследования на Java, как показано ниже.

типы

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

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

Чтобы никто не мог наследовать класс просто используйте модификатор доступа final перед названием класса. (final class Nameclass <> )

Средняя оценка / 5. Количество голосов:

Спасибо, помогите другим - напишите комментарий, добавьте информации к статье.

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

Почему Java не поддерживает множественное наследование?
Рассмотрим приведенный ниже код Java. Это показывает ошибку.

// Первый родительский класс


// Второй родительский класс


// Ошибка: тест наследуется от нескольких
// классы

class Test extends Parent1, Parent2

public static void main(String args[])

Test t = new Test();

Из кода мы видим, что при вызове метода fun () с использованием объекта Test будут возникать сложности, такие как вызов метода fun () Parent1 или метода fun () Parent2.

1. Алмазная проблема:

// Гранд родительский класс в алмазе


// Первый родительский класс

class Parent1 extends GrandParent


// Второй родительский класс

class Parent2 extends GrandParent


// Ошибка: тест наследуется от нескольких
// классы

class Test extends Parent1, Parent2

public static void main(String args[])

Test t = new Test();

Из кода мы видим, что: при вызове метода fun () с использованием объекта Test возникнут сложности, такие как вызов метода fun () метода Child () или метода child () Child.

Поэтому во избежание таких осложнений Java не поддерживает множественное наследование классов.

2. Простота. Многократное наследование не поддерживается Java с использованием классов, поэтому сложность, возникающая из-за множественного наследования, очень сложна. Это создает проблему во время различных операций, таких как приведение, построение цепочки и т. Д., И главная причина в том, что существует очень мало сценариев, в которых нам действительно нужно множественное наследование, поэтому лучше его опустить, чтобы сделать вещи простыми и понятными.

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

// Простая Java-программа для демонстрации нескольких
// наследование через методы по умолчанию.

Читайте также: