Может ли 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();
}

person gstackoverflow    schedule 21.09.2015    source источник
comment
Для динамической реализации того, что происходит AFAIK, есть этот зверь: java.lang.invoke.LambdaMetafactory   -  person zapl    schedule 21.09.2015
comment
Обратите внимание, что объявление пустого класса, например, для вашего class Test, неявно имеет конструктор без аргументов. Вот почему вы можете написать new Test() и заставить его работать, независимо от того, почему лямбда-выражение или ссылка на метод этого конструктора работают.   -  person Stuart Marks    schedule 21.09.2015
comment
@Sotirios Delimanolis, возможно, первый комментарий к связанному вопросу более актуален   -  person gstackoverflow    schedule 22.09.2015


Ответы (3)


Интерфейс Supplier имеет один ( функциональный) метод, который:

  • не принимает никаких параметров;
  • возвращает объект.

Следовательно, любой метод, соответствующий этим двум пунктам, соответствует функциональному контракту Supplier (поскольку методы будут иметь одинаковую сигнатуру).

Здесь рассматриваемый метод является ссылкой на метод. Он не принимает никаких параметров и возвращает новый экземпляр Test. Вы можете переписать его на:

method(() -> new Test());

Test::new в синтаксическом сахаре для этого лямбда-выражения.

person Tunaki    schedule 21.09.2015
comment
Таким образом, если ответить на вопрос из моей темы - да, ссылка на метод была придумана для реализации динамического интерфейса. - person gstackoverflow; 22.09.2015

Test::new — это ссылка на метод. Вместо добавления нового объяснения стоит взглянуть на руководство по ссылки на методы как это объясняет их довольно хорошо.

Прямой ответ на ваш вопрос заключается в том, что Supplier является функциональным интерфейсом, что означает, что он имеет один метод, отличный от значения по умолчанию. Конструктор для Test имеет точно такую ​​же сигнатуру (без аргументов, возвращает Test), поэтому на него можно напрямую ссылаться для создания анонимного Supplier.

Существует четыре разновидности ссылок на методы: ознакомьтесь с учебным пособием, чтобы понять их все.

person sprinter    schedule 21.09.2015
comment
Таким образом, эта функция позволяет старым классам реализовать вновь созданный интерфейс. Вот это да! - person gstackoverflow; 21.09.2015
comment
@gstackoverflow Да, это правильно. Пока подписи совпадают, вы можете обратиться к методу для создания экземпляра интерфейса. При правильном использовании он может существенно улучшить читаемость кода. - person sprinter; 21.09.2015

Это может быть Function, а не поставщик, если требуется аргумент. Но ссылки на методы могут ссылаться на конструкторы точно так же, как и на методы; у них просто смешное имя (new).

В учебнике по Java есть четыре типа ссылок на методы:

Kind                              Example
-------------------------------   ------------------------------------
Reference to a static method      ContainingClass::staticMethodName
Reference to an instance method   containingObject::instanceMethodName
of a particular object  
Reference to an instance method   ContainingType::methodName
of an arbitrary object of a 
particular type
Reference to a constructor        ClassName::new
person erickson    schedule 21.09.2015