Может ли Java 8 реализовать интерфейс на лету для ссылки на метод?
Я изучаю новые возможности Java 8.
Я играю на разных примерах и обнаружил странное поведение:
public static void main(String[] args) {
method(Test::new);
}
static class Test{
}
private static void method(Supplier<Test> testSupplier){
Test test = testSupplier.get();
}
Этот код успешно компилируется, но я понятия не имею, как он работает.
Почему Test::new
приемлемо в качестве поставщика?
Интерфейс поставщика выглядит очень просто:
@FunctionalInterface
public interface Supplier<T> {
T get();
}
3 ответа
Supplier
Интерфейс имеет единственный (функциональный) метод, который:
- не принимает никаких параметров;
- возвращает объект.
Поэтому любой метод, соответствующий этим двум пунктам, соответствует функциональному договору Supplier
(потому что методы будут иметь одинаковую подпись).
Здесь рассматриваемый метод является ссылкой на метод. Он не принимает параметров и возвращает новый экземпляр Test
, Вы можете переписать его так:
method(() -> new Test());
Test::new
в синтаксическом сахаре для этого лямбда-выражения.
Test::new
является ссылкой на метод. Вместо того, чтобы добавлять новое объяснение, стоит взглянуть на учебник для ссылок на методы, так как он объясняет их довольно хорошо.
Прямой ответ на ваш вопрос таков: Supplier
является функциональным интерфейсом - это означает, что он имеет единственный метод, отличный от метода по умолчанию. Конструктор для Test
имеет точно такую же подпись (без аргументов, возвращает Test
) и так можно напрямую ссылаться на создание анонимного Supplier
,
Существует четыре разновидности ссылок на методы: ознакомьтесь с руководством, чтобы понять их все.
Это может быть Function
, а не поставщик, если аргумент требуется. Но ссылки на методы могут ссылаться на конструкторы так же, как они ссылаются на методы; у них просто смешное имя (new
).
Из Учебного руководства по Java есть четыре вида ссылок на методы:
Добрый пример ------------------------------- ------------------- ----------------- Ссылка на статический метод ConistingClass::staticMethodName Ссылка на метод экземпляра, содержащий Object::instanceMethodName конкретного объекта Ссылка на метод экземпляра ContainedType::methodName произвольного объекта конкретный тип Ссылка на конструктор ClassName::new