Java 8 добавить метод расширения/по умолчанию в класс
Я ищу Java-эквивалент функции расширения С#. Теперь я читал о методах по умолчанию Java 8, но, насколько я могу судить, я могу только добавить их к интерфейсам...
... есть ли какая-либо функция языка, которая позволит мне написать метод расширения для конечного класса, который не реализует интерфейс? (Я бы не стал его обертывать...)
Ответы
Ответ 1
Методы расширения С# - это просто синтаксический сахар для статических методов, которые принимают расширенный тип в качестве первого аргумента. Методы Java по умолчанию - это нечто совершенно другое. Чтобы имитировать методы расширения С#, просто напишите обычные статические методы. Однако у вас не будет синтаксического сахара; Java не имеет этой функции.
Java-методы по умолчанию - это реальные методы. Например, они могут быть переопределены. Рассмотрим класс X
, наследующий от интерфейса I
, который объявляет метод по умолчанию foo()
. Если X
или любой из его суперклассов не объявляет собственный foo()
метод, то X
получит реализацию foo()
I
. Теперь подкласс Y
of X
может переопределить X.foo()
как обычный метод. Таким образом, методы по умолчанию - это не только синтаксический сахар. Они являются реальными расширениями механизма переопределения метода и наследования, которые невозможно перенести другими языковыми функциями.
Способы по умолчанию даже требуют специальной поддержки VM, поэтому они даже не являются функцией только для компилятора: во время загрузки класса иерархия класса должна быть проверена, чтобы определить, какие методы по умолчанию они наследуют. Таким образом, это решение принимается во время выполнения, а не во время компиляции. Самое интересное в том, что вам не нужно перекомпилировать класс, когда интерфейс, который он наследует, получает новый метод по умолчанию: VM во время загрузки класса назначает ему новый метод.
Ответ 2
Методы расширения С# являются статическими и use-site, тогда как методы по умолчанию Java являются виртуальными и site-объявлениями.
То, на что я надеюсь, вы надеетесь, это способность "обезьяны-патч" использовать метод в класс, который вы не контролируете, но Java не дает вам этого (по дизайну, он был рассмотрен и отклонен).
Другим преимуществом методов по умолчанию над подходом С# является то, что они являются отражательно открываемыми и фактически извне не выглядят иначе, чем обычные методы интерфейса.
Единственным преимуществом методов расширения С# над методами Java по умолчанию является то, что с помощью генерируемых генераторов С#, методы расширения вводятся в типы, а не классы, поэтому вы можете ввести метод sum()
в List<int>
.
Ответ 3
Java не имеет методов расширения. Методы по умолчанию не являются методами расширения. Посмотрите на каждую функцию.
Методы Java по умолчанию
Проблемы решены:
- Многие объекты могут реализовать один и тот же интерфейс, и все они могут использовать одну и ту же реализацию для метода. Базовый класс может решить эту проблему, но только если разработчики интерфейса уже не имеют базового класса, поскольку java не поддерживает множественное наследование.
- API хотел бы добавить метод к интерфейсу, не нарушая пользователей API. Добавление метода с реализацией по умолчанию решает это.
Java-методы по умолчанию - это функция добавления реализации по умолчанию в интерфейс. Таким образом, объекты, расширяющие интерфейс, не должны реализовывать метод, они могут просто использовать метод по умолчанию.
interface IA { default public int AddOne(int i) { return i + 1; } }
Любой объект, реализующий IA, не должен реализовывать AddOne, поскольку используется метод по умолчанию, который будет использоваться.
public class MyClass implements IA { /* No AddOne implementation needed */ }
С# не хватает этой функции и будет значительно улучшена, добавив эту функцию. (Обновление: функция, входящая в С# 8)
Метод расширения С#
Проблемы решены:
- Возможность добавлять методы к закрытым классам.
- Возможность добавлять методы к классам из сторонних библиотек без принудительного наследования.
- Возможность добавлять методы для моделирования классов в средах, где методы в классах моделей не допускаются по причинам соглашения.
Пример: Строка типа является закрытым классом в С#. Вы не можете наследовать строку, поскольку она запечатана. Но вы можете добавлять методы, которые вы можете вызывать из строки.
var a = "mystring";
a.MyExtensionMethed()
Java не имеет этой функции и будет значительно улучшена, добавив эту функцию.
Заключение
Совсем не похоже на методы Java по умолчанию и возможности метода расширения С#. Они совершенно разные и решают совершенно разные проблемы.
Ответ 4
Возможно, существуют методы расширения с некоторыми трюками.
Вы можете попробовать Lombok или XTend. Хотя методы расширения не связаны с реализацией Java-версии, оба Lombok и XTend предлагают полностью работающее решение.
Ломбок - это простая автономная система обработки кода, которая делает большую часть критичных для Java конкретных проблем менее болезненными, включая методы расширения:
https://projectlombok.org/features/experimental/ExtensionMethod.html
Xtend http://www.eclipse.org/xtend/ переходит на несколько световых лет вперед и реализует язык, который представляет собой комбинацию лучших частей современных языков, таких как Scala поверх системы Java и Java. Это позволяет реализовать некоторые классы в Xtend и других на Java в рамках одного и того же проекта. Код Xtend соответствует действующему Java-коду, поэтому магия JVM не происходит под капотом. С другой стороны, это слишком много, если у вас отсутствуют только методы расширения.
JPropel https://github.com/nicholas22/jpropel-light реализует методы расширения стиля LINQ в Java с использованием Lombok. Это может стоить заглянуть:)