Il terzo argomento al metodo bootstrap, che hai nominato lambdaType
, è il invocato tipo delle associate invokedynamic
istruzione (normalmente compilata dalla JVM). La semantica è definita dal metodo bootstrap e nel caso dello LambdaMetaFactory
, specifica l'interfaccia funzionale come tipo di ritorno (il tipo dell'oggetto da costruire) e i valori da acquisire come tipo di parametro (il tipo di valori da consumare quando costruendo un'istanza lambda).
Quindi, al fine di catturare this
, è necessario aggiungere il tipo di this
al vostro tipo invocato e superare this
come argomento per la chiamata invokeExact
:
public class Test {
public static void main(String... arg) throws Throwable {
System.out.println(new Test().foo().getAsInt());
}
public IntSupplier foo() throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(int.class),
invokedType = MethodType.methodType(IntSupplier.class, Test.class);
MethodHandle methodHandle = lookup.findVirtual(getClass(), "fortyTwo", methodType);
CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",
invokedType, methodType, methodHandle, methodType);
return (IntSupplier) callSite.getTarget().invokeExact(this);
}
public int fortyTwo() {
return 42;
}
}
Se si desidera catturare più valori, è devi aggiungerli alla firma nel giusto ordine. Ad esempio, per acquisire un altro int
valore:
public class Test {
public static void main(String... arg) throws Throwable {
System.out.println(new Test().foo(100).getAsInt());
}
public IntSupplier foo(int capture) throws Throwable {
MethodHandles.Lookup lookup = MethodHandles.lookup();
MethodType methodType = MethodType.methodType(int.class, int.class),
functionType = MethodType.methodType(int.class),
invokedType = MethodType.methodType(IntSupplier.class, Test.class, int.class);
MethodHandle methodHandle=lookup.findVirtual(getClass(),"addFortyTwo",methodType);
CallSite callSite = LambdaMetafactory.metafactory(lookup, "getAsInt",
invokedType, functionType, methodHandle, functionType);
return (IntSupplier) callSite.getTarget().invokeExact(this, capture);
}
public int addFortyTwo(int valueToAdd) {
return 42+valueToAdd;
}
}
Il metodo di destinazione avrà una firma costituito dal tipo this
, se non static
, seguito da tutti i tipi di parametri. I valori di cattura verranno mappati in base ai tipi di questa firma da sinistra a destra e i restanti tipi di parametri, se presenti, contribuiscono alla firma funzionale, quindi devono corrispondere ai tipi di parametri del metodo interface
.
Ciò implica che quando non ci sono valori acquisiti e il metodo di destinazione non è static
, il tipo di ricevitore del metodo potrebbe essere associato al primo tipo di firma funzionale, come in ToIntFunction<String> f=String::length;
.
Immagino che questo serva a capire come lambdas funzioni internamente, perché altrimenti restituiresti il nuovo IntSupplier() {...}; 'senza magia. – immibis
Quello che non capisco, è il commento "Non sarebbe normalmente virtuale". – Holger