Подтвердить что ты не робот

Java 8 добавить метод расширения/по умолчанию в класс

Я ищу Java-эквивалент функции расширения С#. Теперь я читал о методах по умолчанию Java 8, но, насколько я могу судить, я могу только добавить их к интерфейсам...

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

4b9b3361

Ответ 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. Это может стоить заглянуть:)