2015-09-21 21 views
19

imparo nuove funzionalità di Java 8.Java 8 può implementare l'interfaccia al volo per il riferimento al metodo?

sto giocando con diversi esempi e ho trovato uno strano comportamento:

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

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

Questo codice viene compilato con successo, ma non ho idea di come funziona.

Perché lo standard Test::new è accettabile come fornitore?

interfaccia Fornitore sembra molto semplice:

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

Per implementare dinamicamente quale tipo di AFAIK accade c'è questa bestia: ['java.lang.invoke.LambdaMetafactory'] (https://docs.oracle.com/javase/8/docs/api/java/lang/ invoke/LambdaMetafactory.html) – zapl

+3

Si noti che una dichiarazione di classe "vuota", come per il 'test di classe', ha implicitamente un costruttore no-arg. Ecco perché puoi scrivere 'new Test()' e farlo funzionare, qualsiasi motivo per cui un metodo lambda o di riferimento a questo costruttore funzioni. –

+0

@Sotirios Delimanolis forse il primo commento alla domanda collegata è più rilevante – gstackoverflow

risposta

19

L'interfaccia Supplier ha un unico metodo (funzionale) che:

  • non prende alcun parametro;
  • restituisce un oggetto.

Pertanto, qualsiasi metodo conforme a questi due punti, è conforme al contratto funzionale di Supplier (poiché i metodi avranno la stessa firma).

Qui, il metodo in questione è un riferimento al metodo. Non richiede parametri e restituisce una nuova istanza di Test. Si potrebbe riscrivere a:

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

Test::new in zucchero sintattico per questa espressione lambda.

+0

Quindi se rispondi alla domanda dal mio soggetto - Sì, il riferimento al metodo è stato inventato per l'implementazione dell'interfaccia dinamica. – gstackoverflow

3

Potrebbe essere una Function, piuttosto che un fornitore, se è richiesto un argomento. Ma i riferimenti al metodo possono riferirsi ai costruttori nello stesso modo in cui fanno riferimento ai metodi; hanno solo un nome divertente (new).

Da the Java Tutorial, ci sono quattro tipi di metodo riferimenti:

 
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 è un riferimento al metodo. Piuttosto che aggiungere una nuova spiegazione, vale la pena dare un'occhiata al tutorial per method references in quanto li spiega abbastanza bene.

La risposta diretta alla tua domanda è che Supplier è un'interfaccia funzionale, ovvero ha un unico metodo non predefinito. Il costruttore per Test ha esattamente la stessa firma (nessun argomento, restituisce Test) e quindi può essere fatto riferimento direttamente per creare un anonimo Supplier.

Esistono quattro tipi di riferimenti al metodo: consulta il tutorial per comprenderli tutti.

+0

Quindi questa funzione consente alle vecchie classi di implementare l'interfaccia appena creata. Wow! – gstackoverflow

+1

@gstackoverflow Sì, è corretto. Finché le firme corrispondono, puoi fare riferimento al metodo per creare un'istanza dell'interfaccia. Se usato bene, può migliorare sostanzialmente la leggibilità del codice. – sprinter