2015-09-21 13 views
19

uczę nowych funkcji Java 8.Czy Java 8 może implementować interfejs w locie, aby uzyskać odwołanie do metody?

gram z różnymi przykładami i znalazłem dziwne zachowanie:

public static void main(String[] args) {  
    method(Test::new); 
} 
static class Test{ 
} 

private static void method(Supplier<Test> testSupplier){ 
    Test test = testSupplier.get(); 
} 

Ten kod kompiluje się pomyślnie, ale nie mam pojęcia jak to działa.

Dlaczego Test::new akceptowalny jako dostawca?

Dostawca interfejs wygląda bardzo prosta:

@FunctionalInterface 
public interface Supplier<T> {  
    T get(); 
} 
+2

Do dynamicznego wdrażania tego typu zdarzeń AFAIK jest ta bestia: ['java.lang.invoke.LambdaMetafactory'] (https://docs.oracle.com/javase/8/docs/api/java/lang/ invoke/LambdaMetafactory.html) – zapl

+3

Należy zauważyć, że "pusta" deklaracja klasy, na przykład dla twojego "testu klasy", domyślnie ma konstruktor no-arg. Dlatego możesz napisać 'new Test()' i sprawić by działało, niezależnie od tego, dlaczego działa odwołanie do lambda lub metody do tego konstruktora. –

+0

@Sotirios Delimanolis może pierwszy komentarz do połączonego pytania jest bardziej odpowiedni – gstackoverflow

Odpowiedz

19

Interfejs Supplier ma pojedynczy (funkcjonalny) sposób, że:

  • nie potrzebuje żadnych parametrów;
  • zwraca obiekt.

Dlatego każda metoda zgodna z tymi dwoma punktami jest zgodna z umową funkcjonalną z Supplier (ponieważ metody będą miały ten sam podpis).

W tym przypadku metoda jest referencją do metody. Nie przyjmuje parametrów i zwraca nowe wystąpienie Test. Można przerobić go na adres:

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

Test::new cukru składniowej dla tego wyrażenia lambda.

+0

Tak więc, jeśli odpowiedź na pytanie z mojego tematu - Tak, odwołanie do metody zostało wymyślone dla dynamicznie implementacji interfejsu. – gstackoverflow

3

To może być Function zamiast dostawcy, jeżeli wymagane jest argument. Jednak odwołania do metod mogą odnosić się do konstruktorów w ten sam sposób, w jaki odnoszą się do metod; po prostu mają zabawne imię (new).

Z the Java Tutorial, istnieją cztery rodzaje odniesienia Metoda:

 
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 
11

Test::new jest odwołaniem do metody. Zamiast dodawać nowe wyjaśnienia warto przyjrzeć się samouczkowi dla method references, ponieważ wyjaśnia on je całkiem dobrze.

Bezpośrednią odpowiedzią na twoje pytanie jest to, że Supplier jest funkcjonalnym interfejsem - co oznacza, że ​​ma jedną inną niż domyślną metodę. Konstruktor dla Test ma dokładnie taką samą sygnaturę (brak argumentów, zwraca Test), więc można bezpośrednio odwoływać się do tworzenia anonimowego Supplier.

Dostępne są cztery smaki odwołań metod: zapoznaj się z samouczkiem, aby je wszystkie zrozumieć.

+0

Dzięki temu ta funkcja pozwala starym klasom implementować nowo utworzony interfejs. Łał! – gstackoverflow

+1

@gstackoverflow Tak, to prawda. Dopóki sygnatury są zgodne, możesz odwołać się do metody tworzenia instancji interfejsu. Przy odpowiednim użyciu może znacznie poprawić czytelność kodu. – sprinter