Java 8 добавить расширение / метод по умолчанию в класс
Я ищу java-эквивалент функции методов расширения C#. Теперь я читал о методах Java 8 по умолчанию, но, насколько я могу видеть, я могу только добавить их к интерфейсам...
...Есть ли какая-либо языковая функция, которая позволит мне написать метод расширения для конечного класса, который не реализует интерфейс? (Мне бы не хотелось его заворачивать...)
4 ответов
методы расширения C# - это просто синтаксический сахар для статических методов, которые принимают расширенный тип в качестве первого аргумента. Методы Java по умолчанию-это нечто совершенно другое. Чтобы имитировать методы расширения C#, просто напишите обычные статические методы. Вы не имеете syntatic сахара; Java не имеют этой функции.
методы Java по умолчанию являются реальными виртуальными методами. Например, их можно переопределить. Рассмотрим класс X
наследование от интерфейса I
что объявит дефолт foo()
метод. Если X
или любой из его супер классов не объявляет собственного foo()
метод, то X
будет foo()
реализация I
. Теперь подкласс Y
of X
можно переопределить X.foo()
обычный способ. Таким образом, методы по умолчанию-это не только синтаксический сахар. Они являются реальными расширениями механизма переопределения и наследования метода, которые не могут быть имитированы другими языковыми функциями.
методы по умолчанию даже требуют специальной VM поддержка, поэтому они даже не являются функцией компилятора: во время загрузки класса необходимо проверить иерархию класса, чтобы определить, какие методы по умолчанию он унаследует. Таким образом, это решение принимается во время выполнения, а не во время компиляции. Самое интересное в этом то, что вам не нужно перекомпилировать класс, когда интерфейс, который он наследует, получает новый метод по умолчанию: VM во время загрузки класса назначит ему этот новый метод.
в C# методы расширения статический и использовать-сайте, тогда как методы Java по умолчанию виртуальный и декларации-сайте.
Я считаю, что вы надеетесь на возможность "обезьяна-патч" метод в класс, который вы не контролируете, но Java не дает вам этого (по дизайну; он был рассмотрен и отклонен.)
еще одно преимущество методов по умолчанию над подходом c# заключается в том, что они рефлективно обнаруживаемые, и на самом деле со стороны, не выглядят иначе, чем" обычные " методы интерфейса.
одним из преимуществ методов расширения C#по сравнению с методами Java по умолчанию является то, что с овеществленными дженериками C#методы расширения вводятся в типы, а не классы, так что вы можете впрыснуть sum()
метод List<int>
.
прежде всего, основное философское различие между методами Java по умолчанию и методами расширения C#заключается в том, что C# позволяет вводить методы в типы вы не контролируете (что, безусловно, удобно для разработчиков), тогда как методы расширения Java являются первоклассной частью API, в котором они появляются (они объявлены в интерфейсе, они рефлективно обнаруживаются и т. д.) Это отражает несколько принципов проектирования; разработчики библиотек должны иметь возможность поддерживать контроль над своими API, а использование библиотек должно быть прозрачным -- calling method x()
по типу Y
это должно означать то же вещи повсюду.
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 */ }
В C# не хватает этой функции и будет значительно улучшена путем добавления этой функции. (Обновление: функция приходит в C# 8)
метод расширения C#
проблемы:- возможность добавления методов в запечатанных классов.
- возможность добавления методов в классы из сторонних библиотек без принудительного наследования.
- возможность добавления методов в классы моделей в среды, в которых методы в классах моделей не разрешены по причинам соглашения.
- возможность intellisense представить вам эти методы.
пример: строка типа является запечатанным классом в C#. Вы не можете наследовать от string, поскольку он запечатан. Но вы можете добавить методы, которые вы можете вызвать из строки.
var a = "mystring";
a.MyExtensionMethed()
Java не хватает этой функции и будет значительно улучшена путем добавления этой функции.
вывод
там нет ничего похожего на методы Java по умолчанию и функции метода расширения C#. Они совершенно разные и решают совершенно разные задачи.
можно иметь методы расширения, с некоторыми трюками.
вы можете попробовать Ломбок или XTend. Хотя методы расширения не поставляются с реализацией Java из коробки, Lombok и XTend предлагают полностью рабочее решение.
Lombok-это простой автономный фреймворк обработки кода, который делает большую часть критикуемых Java-проблем менее болезненными, включая расширение методы: https://projectlombok.org/features/experimental/ExtensionMethod.html
Xtend http://www.eclipse.org/xtend/ идет несколько световых лет вперед и реализует язык, который представляет собой комбинацию лучших частей современных языков, таких как Scala поверх Java и Java type system. Это позволяет реализовать некоторые классы в Xtend и другие в Java в рамках одного проекта. Код Xtend соответствует действительному Java-коду, поэтому магия JVM не происходит под капюшон. С другой стороны, это слишком много, если у вас отсутствуют только методы расширения.
JPropel https://github.com/nicholas22/jpropel-light реализует методы расширения стиля LINQ в Java с использованием Ломбока. Возможно, стоит заглянуть:)