Вопрос

Я слышал, что есть способ обмануть одиночное наследование и реализовать множественное наследование в Java.Кто-нибудь знает, как это реализовать (без использования интерфейса)?

Просто из любопытства ;-)

Это было полезно?

Решение

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

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

Другие советы

ОдинокийМножественное наследование не поддерживается Java, вместо этого у него есть интерфейсы, служащие той же цели.Если вы непреклонны в использовании множественного наследования, это следует сделать на C++.

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

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

Я считаю, что основная причина, по которой Java не поддерживает множественное наследование, та же, что и в C#;все объекты в конечном итоге являются производными от Object, и наличие нескольких путей к одному и тому же базовому классу является неоднозначным для компилятора.Неоднозначно == Плохо, поэтому компилятор этого не допускает.

Вместо этого вы можете моделировать множественное наследование посредством делегирования.Видеть Эта статья для примера.

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

На самом деле это просто позволяет вам добавлять дополнительные интерфейсы и делегировать их вызовы другому экземпляру во время выполнения.

Как человек, который наставляет и обучает новых разработчиков, я был бы в ужасе, если бы кто-нибудь показал мне код, который делает это.Reflection — один из тех инструментов, которые вам действительно необходимо понять и хорошо разобраться в Java, прежде чем приступить к ним.Лично я делал это только один раз, и это было сделано для того, чтобы написать какой-то код, который я не мог контролировать, реализовать некоторые интерфейсы, которые ожидал какой-то другой код, над которым я не имел контроля (это был быстрый хак, поэтому мне не пришлось писать и поддерживать слишком много связующего кода).

Использовать interfaceс.Вы можете реализовать столько, сколько захотите.Обычно вы можете использовать какой-либо вариант на Составной шаблон (GoF) чтобы иметь возможность повторно использовать код реализации, если это желательно.

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

Java обеспечивает наследование интерфейса реализует механизм и ты может иметь множественное наследование интерфейсов.

Наследование реализации – это простирается механизм, и у вас есть только одна его версия.Ты Действительно нужно множественное наследование реализации?Могу поспорить, что нет, это полно неприятных последствий, если вы все равно не программист Eiffel.

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

JAVA не поддерживает множественное наследование.

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

Обычно, когда кто-то предлагает множественное наследование в C# или JAVA, это связано с тем, что «они могли бы» в C++.Я сторонник фразы «То, что ты можешь, не значит, что ты должен».Поскольку C# и JAVA не поддерживают его, зачем пытаться заставить его делать то, для чего он не предназначен.Это не означает, что существуют уникальные случаи, когда эмполия является допустимым методом, просто код обычно можно рефакторить, чтобы он не требовался.

Я подумал об этом еще немного и понял, что, хотя динамические прокси будут работать (именно так работает RMI (используется?), если вам действительно нужна такая функциональность, вам лучше взглянуть на аспектно-ориентированное программирование (АОП), используя что-то вроде AspectJ (eclipse.org/aspectj).

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

Как отмечали все остальные, желание/необходимость множественного наследования обычно указывает на то, что вы не подходите к проблеме с правильной точки зрения.Для начала запомните принцип GoF: «предпочитать композицию наследованию»!

Была попытка внедрить миксины в Java.Проверьте эту ссылку: http://www.disi.unige.it/person/LagorioG/jam/

Используя внутренние классы, C++ иногда предпочитает именно это: Идиома внутреннего класса.

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

public class parents implements first, second{

}

но помните, что вам придется переопределить методы, объявленные в интерфейсах.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top