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




JAVA не поддерживает множественное наследование.
Вы можете заставить его реализовать несколько интерфейсов, и некоторые видят в этом способ решения проблемы. Лично мне еще предстоит использовать множественное наследование, поэтому я не могу понять его привлекательность.
Обычно, когда кто-то предлагает множественное наследование в C# или JAVA, это связано с тем, что «они могли» в C++. Я фанат фразы «просто потому, что ты не можешь этого сделать, не значит, что ты должен». Поскольку C# и JAVA его не поддерживают, зачем пытаться заставить его делать то, для чего он не предназначен. Это не означает, что существуют уникальные случаи, когда это действенный метод эмполии, просто код обычно можно отредактировать, чтобы он не нуждался в нем.
Вы, вероятно, имеете в виду, что он не поддерживает наследование несколько.
Наследование признаков (по сути, смешанное наследование) в Scala показывает несколько способов, которыми может быть полезно множественное наследование, хотя решение Java не реализовывать его вполне понятно, поскольку многие реализации в конечном итоге становятся излишне сложными для размышлений.
Использование композиции вместо наследования обычно помогает решить эту проблему. На самом деле это также очень помогает с тестируемостью, так что в целом это хорошая практика.
Если вы просто хотите, чтобы ваш тип «вел себя» как несколько других типов, вы можете наследовать от любого количества интерфейсов; однако, очевидно, что вы не можете «позаимствовать» детали реализации из них.
Используйте interface. Вы можете реализовать столько, сколько захотите. Обычно вы можете использовать какой-либо вариант Составной узор (GoF), чтобы иметь возможность повторно использовать код реализации, если это желательно.
Я считаю, что основная причина того, что Java не поддерживает множественное наследование, та же, что и C#; все объекты в конечном итоге являются производными от Object, и наличие нескольких путей к одному и тому же базовому классу неоднозначно для компилятора. Неоднозначно == Плохо, поэтому компилятор этого не допускает.
Вместо этого вы можете смоделировать множественное наследование посредством делегирования. См. Пример Эта статья.
На самом деле совместное использование Object не является неоднозначным для компилятора. Это становится неоднозначным только тогда, когда методы определены в разных классах. Итак, если одна ветвь переопределяет хэш-код, а другая - нет. В таких случаях программисту придется сделать выбор.
Вы можете немного обмануть его (и я немного подчеркиваю), используя экземпляры java.lang.reflect.Proxy.
Это действительно просто позволяет вам добавлять дополнительные интерфейсы и делегировать их вызовы другому экземпляру во время выполнения.
Как человек, который наставляет и обучает новых разработчиков, я был бы в ужасе, если бы кто-нибудь показал мне код, который делал это. Отражение - один из тех инструментов, которые вам действительно нужно понять и хорошо разбираться в Java, прежде чем приступать к делу. Лично я делал это только один раз, и это было для создания кода, над которым я не мог контролировать, реализовать некоторые интерфейсы, некоторые ожидался другой код, который я не мог контролировать (это был быстрый взлом, поэтому мне не пришлось писать и поддерживать слишком много связующего кода).
Да, это «изящный трюк», но его не стоит использовать в производственном коде!
но для использования прокси вам нужны интерфейсы. ОП: "... без использования интерфейса ..."
Вы должны быть осторожны, чтобы различать наследование интерфейса (по сути, наследование контракта для предоставления определенных возможностей) от наследования реализации (наследования механизмов реализации).
Java обеспечивает наследование интерфейсов с помощью механизма орудия, и у вас может есть множественное наследование интерфейсов.
Наследование реализации - это механизм расширяет, и у вас есть только одна его версия. Вам В самом деле нужно наследование множественных реализаций? Держу пари, что нет, это полно неприятных последствий, если вы все равно не программист Eiffel.
Вы, вероятно, могли бы «смоделировать» это, явно управляя набором суперклассов и используя отражение для поиска целевого метода во всех суперклассах. Я бы не хотел делать это в продакшене, но это может быть интересная игрушечная программа. Вы, вероятно, могли бы сделать много странных вещей, используя отражение, создавая классы на лету и программно вызывая компилятор.
Я подумал об этом немного больше и понял, что, хотя динамические прокси будут работать (это то, как RMI (используется?) Для работы), если вам действительно нужна такая функциональность, вам лучше взглянуть на аспектно-ориентированное программирование (AOP), используя что-то вроде AspectJ (eclipse.org/aspectj).
Таким образом, вы можете получить несколько различных аспектов в классе, давая вам псевдомиксиновое наследование, без ужасно хрупкой иерархии наследования.
Как уже отмечали все остальные, желание / необходимость множественного наследования обычно указывает на то, что вы не подходите к проблеме с правильной точки зрения. Вспомните для начала принцип GoF «предпочитать композицию наследованию»!
Была попытка внедрить миксины в Java. Проверьте эту ссылку: http://www.disi.unige.it/person/LagorioG/jam/
Конечно, можете, но это непросто, и вам стоит подумать, хотите ли вы пойти по этому пути. Идея состоит в том, чтобы использовать наследование на основе области видимости в сочетании с наследованием на основе типов. Это типичный разговор о том, что для внутренних целей внутренние классы «наследуют» методы и поля внешнего класса. Это немного похоже на миксины, где внешний класс смешивается с внутренним, но не так безопасно, поскольку вы можете изменить состояние внешнего класса, а также использовать его методы. Гилад Браха (один из главных разработчиков языка Java) написал бумага, обсуждая это. Итак, предположим, что вы хотите поделиться некоторыми методами для внутреннего использования между некоторыми несвязанными классами (например, для обработки строк), вы можете создать их подклассы как внутренние классы класса, который имеет все необходимые методы, и подклассы могут использовать методы как из своих суперклассов, так и из внешнего класса.
В любом случае, это сложно для сложных классов, и вы можете получить большую часть функциональности, используя статический импорт (начиная с java 5). Тем не менее, отличный вопрос для собеседований и викторин в пабах ;-)
здесь небольшая опечатка, я бы исправил это, но у меня пока недостаточно репутации. 'создать подклассы ТО как'
@TygerKrash Для редактирования сообщений репутация не нужна: SE создан как Wiki.
Одинокий Java не поддерживает множественное наследование, вместо этого у него есть интерфейсы, которые служат той же цели. Если вы категорически против использования множественного наследования, это следует делать на C++.
Используя внутренние классы, C++ иногда предпочитает именно это: Идиома внутреннего класса.
Да, вы можете сказать, что это уловка, и это очень интересно, что вы не можете наследовать несколько классов одному классу, но можно реализовать несколько интерфейсов для такого класса, как
public class parents implements first, second{
}
но помните, вы должны переопределить методы, объявленные в интерфейсах.
Это совсем другая мысль.