2 回答

TA貢獻1828條經(jīng)驗 獲得超6個贊
或者我應(yīng)該創(chuàng)建一個實例并以某種方式將它傳遞給 API?
是的。HomeHandler::handle
是一個實例方法,這意味著您需要一個實例來創(chuàng)建功能接口包裝器,或者每次調(diào)用它時都傳遞一個實例(對于它Handler
不能作為 FunctionalInterface 類型工作)。
要使用捕獲的實例,您應(yīng)該:
更改
factoryMethodType
為也采取HomeHandler
實例更改
functionMethodType
為 SAM 的擦除類型,該類型以 anObject
作為參數(shù)。將
instantiatedMethodType
參數(shù)更改為沒有捕獲HomeHandler
實例的目標(biāo)方法句柄的類型(因為它已被捕獲,因此您不再需要它作為參數(shù))。創(chuàng)建功能接口接口時傳遞
HomeHandler
to的實例invokeExact
。
——
Class<?> homeHandlerClass = HomeHandler.class;
Method method = homeHandlerClass.getDeclaredMethod(
"handle", RoutingContext.class);
Lookup lookup = MethodHandles.lookup();
MethodHandle mh = lookup.unreflect(method);
MethodType factoryMethodType = MethodType.methodType(Handler.class, HomeHandler.class);
MethodType functionMethodType = MethodType.methodType(void.class, Object.class);
MethodHandle implementationMethodHandle = mh;
Handler<RoutingContext> lambda =
(Handler<RoutingContext>) LambdaMetafactory.metafactory(
lookup,
"handle",
factoryMethodType,
functionMethodType,
implementationMethodHandle,
implementationMethodHandle.type().dropParameterTypes(0, 1))
.getTarget()
.invokeExact(new HomeHandler()); // capturing instance
lambda.handle(ctx);
當(dāng)然,因為HomeHandlerimplements Handler,你可以直接使用捕獲的實例;
new HomeHandler().handle(ctx);
或者利用編譯器生成元工廠代碼,它也使用invokedynamic,這意味著CallSite返回的 byLambdaMetafactory.metafactory只會被創(chuàng)建一次:
Handler<RoutingContext> lambda = new HomeHandler()::handle;
lambda.handle(ctx);
或者,如果功能接口類型是靜態(tài)知道的:
MethodHandle theHandle = ...
Object theInstance = ...
MethodHandle adapted = theHandle.bindTo(theInstance);
Handler<RoutingContext> lambda = ctxt -> {
try {
adapted.invokeExact(ctxt);
} catch (Throwable e) {
throw new RuntimeException(e);
}
};
lambda.handle(new RoutingContext());

TA貢獻1859條經(jīng)驗 獲得超6個贊
既然你說“很遺憾 LambdaMetaFactory API 如此復(fù)雜”,那么應(yīng)該提到它可以做得更簡單。
首先,在使用時LambdaMetaFactory,直接使用它:
Lookup lookup = MethodHandles.lookup();
MethodType fType = MethodType.methodType(void.class, RoutingContext.class);
MethodHandle mh = lookup.findVirtual(HomeHandler.class, "handle", fType);
Handler<RoutingContext> lambda = (Handler<RoutingContext>) LambdaMetafactory.metafactory(
lookup, "handle", MethodType.methodType(Handler.class, HomeHandler.class),
fType.erase(), mh, fType).getTarget().invokeExact(new HomeHandler());
您將使用綁定接收器調(diào)用實例方法,并且不包括接收器的目標(biāo)方法的類型與instantiatedMethodType參數(shù)相同。此外,由于Tin的邊界Handler<T>是Object,您可以簡單地使用erase()該方法類型來獲取samMethodType參數(shù)的擦除簽名。
它并不總是那么簡單。考慮將方法綁定static int method(int x)到Consumer<Integer>. 那么,samMethodType參數(shù)是(Object)void,instantiatedMethodType參數(shù)是(Integer)void,而目標(biāo)方法的簽名是int(int)。您需要所有這些參數(shù)來正確描述要生成的代碼??紤]到其他(前三個)參數(shù)通常由 JVM 填充,這種方法已經(jīng)只需要必要的最小值。
其次,如果您不需要最高性能,則可以簡單地使用Proxy基于實現(xiàn)的實現(xiàn):
MethodHandle mh = MethodHandles.lookup().findVirtual(HomeHandler.class,
"handle", MethodType.methodType(void.class, RoutingContext.class));
Handler<RoutingContext> lambda = MethodHandleProxies.asInterfaceInstance(
Handler.class, mh.bindTo(new HomeHandler()));
添加回答
舉報