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 по умолчанию

проблемы:
  1. многие объекты могут реализовывать один и тот же интерфейс, и все они могут использовать одну и ту же реализацию для метода. Базовый класс может решить эту проблему, но только если у реализаторов интерфейса еще нет базового класса, поскольку java не поддерживает несколько наследование.
  2. 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#

проблемы:
  1. возможность добавления методов в запечатанных классов.
  2. возможность добавления методов в классы из сторонних библиотек без принудительного наследования.
  3. возможность добавления методов в классы моделей в среды, в которых методы в классах моделей не разрешены по причинам соглашения.
  4. возможность 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 с использованием Ломбока. Возможно, стоит заглянуть:)