- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试通过 LambdaMetafactory 动态创建 BiConsumer 类型的方法引用。我试图应用在 https://www.cuba-platform.com/blog/think-twice-before-using-reflection/ 上找到的两种方法- createVoidHandlerLambda 和此处 Create BiConsumer as Field setter without reflection霍尔格的回答。
但是在这两种情况下我都遇到了以下错误:
Exception in thread "main" java.lang.AbstractMethodError: Receiver class org.home.ref.App$$Lambda$15/0x0000000800066040 does not define or inherit an implementation of the resolved method abstract accept(Ljava/lang/Object;Ljava/lang/Object;)V of interface java.util.function.BiConsumer.
at org.home.ref.App.main(App.java:20)
我的代码是这样的:
public class App {
public static void main(String[] args) throws Throwable {
MyClass myClass = new MyClass();
BiConsumer<MyClass, Boolean> setValid = MyClass::setValid;
setValid.accept(myClass, true);
BiConsumer<MyClass, Boolean> mappingMethodReferences = createHandlerLambda(MyClass.class);
mappingMethodReferences.accept(myClass, true);
}
@SuppressWarnings("unchecked")
public static BiConsumer<MyClass, Boolean> createHandlerLambda(Class<?> classType) throws Throwable {
Method method = classType.getMethod("setValid", boolean.class);
MethodHandles.Lookup caller = MethodHandles.lookup();
CallSite site = LambdaMetafactory.metafactory(caller,
"accept",
MethodType.methodType(BiConsumer.class),
MethodType.methodType(void.class, MyClass.class, boolean.class),
caller.findVirtual(classType, method.getName(),
MethodType.methodType(void.class, method.getParameterTypes()[0])),
MethodType.methodType(void.class, classType, method.getParameterTypes()[0]));
MethodHandle factory = site.getTarget();
return (BiConsumer<MyClass, Boolean>) factory.invoke();
}
public static <C, V> BiConsumer<C, V> createSetter(Class<?> classType) throws Throwable {
Field field = classType.getDeclaredField("valid");
MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle setter = lookup.unreflectSetter(field);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"accept", MethodType.methodType(BiConsumer.class, MethodHandle.class),
setter.type().erase(), MethodHandles.exactInvoker(setter.type()), setter.type());
return (BiConsumer<C, V>)site.getTarget().invokeExact(setter);
}
}
MyClass 看起来像这样:
public class MyClass {
public boolean valid;
public void setValid(boolean valid) {
this.valid = valid;
System.out.println("Called setValid");
}
}
我将不胜感激。
编辑#1。在咨询了@Holger 之后,我将 createSetter 方法修改为:
@SuppressWarnings("unchecked")
public static <C, V> BiConsumer<C, V> createSetter(Class<?> classType) throws Throwable {
Field field = classType.getDeclaredField("valid");
MethodHandles.Lookup lookup = MethodHandles.lookup();
final MethodHandle setter = lookup.unreflectSetter(field);
MethodType type = setter.type();
if(field.getType().isPrimitive())
type = type.wrap().changeReturnType(void.class);
final CallSite site = LambdaMetafactory.metafactory(lookup,
"accept", MethodType.methodType(BiConsumer.class, MethodHandle.class),
type.erase(), MethodHandles.exactInvoker(setter.type()), type);
return (BiConsumer<C, V>)site.getTarget().invokeExact(setter);
}
现在此方法不会抛出初始异常,尽管似乎对该方法引用调用 accept 无效。我没有在该调用的日志中看到“Called setValid”。仅适用于 MyClass::setValid;
最佳答案
请注意,您对 getMethod
的使用和 caller.findVirtual(…)
因为同样的方法是多余的。如果您的起点是 Method
, 你可以使用 unreflect
,例如
Method method = classType.getMethod("setValid", boolean.class);
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodHandle target = caller.unreflect(method);
当您动态地发现方法和/或正在寻找过程中的注释等其他工件时,这可能很有用。否则,只得到 MethodHandle
通过findVirtual
就够了。
然后,您必须了解三种不同的函数类型:
(MyClass,boolean) → void
BiConsumer<MyClass, Boolean>
,即 (MyClass,Boolean) → void
BiConsumer
的删除类型接口(interface),即(Object,Object) → void
只有正确指定所有三种类型才能告诉工厂它必须实现该方法
void accept(Object,Object)
使用将第一个参数转换为 MyClass
的代码第二个是Boolean
, 然后将第二个参数展开到 boolean
, 最终调用目标方法。
我们可以显式指定类型,但为了使代码尽可能可重用,我们可以调用 type()
在目标上,然后使用适配器方法。
wrap()
会将所有原始类型转换为它们的包装器类型。不幸的是,这也意味着将返回类型转换为 Void
, 所以我们必须将它设置回 void
再次。erase()
会将所有引用类型转换为 Object
但保留所有原始类型。所以将它应用于 instantiatedMethodType 给我们删除的类型。java.util.function
中的接口(interface),它是。提高可重用性的另一点是为方法接收类使用实际类型参数,因为我们无论如何都将类作为参数:
public static <T>
BiConsumer<T, Boolean> createHandlerLambda(Class<T> classType) throws Throwable {
MethodHandles.Lookup caller = MethodHandles.lookup();
MethodHandle target = caller.findVirtual(classType, "setValid",
MethodType.methodType(void.class, boolean.class));
MethodType instantiated = target.type().wrap().changeReturnType(void.class);
CallSite site = LambdaMetafactory.metafactory(caller,
"accept", MethodType.methodType(BiConsumer.class),
instantiated.erase(), target, instantiated);
return (BiConsumer<T, Boolean>)site.getTarget().invoke();
}
关于java - 从 LambdaMetafactory 创建 BiConsumer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61592566/
我正在尝试使用 Java 的 LambdaMetaFactory动态实现通用 lambda,Handler : public class RoutingContext { // ... } @
当我调用 metafactory 时出现异常。它说: java.lang.invoke.LambdaConversionException: Incorrect number of param
尽管阅读了我所知道的所有文档,但我无法解决使用 lambda 执行方法的问题。为了提供一些背景知识,我的用例是一个插件系统。我正在使用可以分配给任何方法的注释 (@EventHandle)。我使用反射
我正在尝试显式使用 LambdaMetafactory.metafactory,我不明白为什么它只适用于 Runnable 功能接口(interface)。例如,此代码执行预期的操作(打印“hello
如何使用 LambdaMetaFactory 为 SAM/功能接口(interface)创建代理对象 即。相当于 public static Object java.lang.reflect.Prox
我正在尝试使用 LambdaMetafactory 来替换反射,但我遇到了一个问题。如果我使用特定的类,那么它会很好地工作,就像这样: MethodHandles.Lookup loo
基于 this stackoverflow answer ,我正在尝试使用反射实例化一个类,然后使用 LambdaMetafactory::metafactory 在其上调用单参数方法(我尝试使用反射
我有一个接口(interface) Action : package action; public interface Action { public String act(); } Simp
在我的工作中,我们有一个用于指定数学公式的 DSL,我们后来将其应用于很多点(以百万计)。 截至今天,我们构建了公式的 AST,并访问每个节点以生成我们所谓的“评估器”。然后,我们将公式的参数传递给评
我想尝试避免调用构造函数的反射,并尝试遵循本文中采用的 LamdaMetaFactory 方法 - Faster alternatives to Java's reflection 我要构建的类如下所
在转换 Java 8 access private member with lambda? 时来自 concrete format至 generic format我找到了 another limita
作为与 Holgers' solution 密切相关的后续问题,为什么取消注释覆盖会破坏下面的工作代码? public static interface StringFunction extends
我正在尝试使用 LambdaMetafactory.metafactory() 在 App.java 的 main 方法中执行带注释的方法: import com.drfits.annotation.
我正在尝试通过 LambdaMetafactory 动态创建 BiConsumer 类型的方法引用。我试图应用在 https://www.cuba-platform.com/blog/think-tw
我有这个工作正常的代码: Method getterMethod = Person.class.getDeclaredMethod("getName"); MethodHandles.Lookup l
我在调用通过调用 LambdaMetafactory#metafactory() 定义的方法时收到了 AbstractMethodError。我不知道我做错了什么导致它。我在网上查看了很多使用 Lam
我有一个简单的 Person 类,它有一个返回 String 的 getName(): public class Person { public String getName() {...}
我包括了AndroidRate library在我的项目中 android { ... compileOptions { sourceCompatibility Jav
我的问题与 Explicit use of LambdaMetafactory 密切相关在该线程中,提供了一些非常好的示例来使用 LambdaMetafactory 访问类的静态方法;但是,我想知道访
我在运行以下代码时遇到问题: public class LambdaTesting { public static void main(String[] args){
我是一名优秀的程序员,十分优秀!