如何用LambdaMetaFactory获取类方法执行时间?遇AbstractMethodError异常
问题根源
- 函数式接口签名不兼容:
GetterFunction的invoke()是无参数无返回值,但目标方法Person.getName()是无参数返回String,两者签名不匹配,LambdaMetafactory无法生成正确实现该接口的类,最终抛出AbstractMethodError。 - LambdaMetafactory参数错误:
- 工厂方法类型(第三个参数)未正确指定,没有考虑到
Person实例作为方法接收者的需求。 - 函数式接口方法类型与目标方法类型不匹配,导致lambda生成逻辑混乱。
- 工厂方法类型(第三个参数)未正确指定,没有考虑到
- 缺失方法接收者:
Person.getName()是实例方法,必须传入Person实例才能调用,当前代码未提供任何实例。 - 语法与API错误:
System.CurrentMilliSeconds()拼写错误(应为System.currentTimeMillis()),静态的main方法无法直接调用非静态的invoke方法,且getterFunction.invoke());多了一个括号。
修复方案(两种可行实现)
方案一:绑定具体Person实例到Lambda
把Person实例绑定到生成的lambda中,无需在调用时重复传入:
public class MyMain { public static void main(String[] args) throws Throwable { // 创建待测试的Person实例 Person person = new Person("Alice"); final MethodHandles.Lookup lookup = MethodHandles.lookup(); // 目标方法getName的类型:无参数,返回String MethodType targetMethodType = MethodType.methodType(String.class); // 函数式接口方法的类型:无参数,返回void(忽略getName的返回值) MethodType interfaceMethodType = MethodType.methodType(void.class); // 工厂方法类型:接收Person实例,返回GetterFunction MethodType factoryMethodType = MethodType.methodType(GetterFunction.class, Person.class); final CallSite site = LambdaMetafactory.metafactory( lookup, "invoke", factoryMethodType, interfaceMethodType, // 绑定Person实例到方法句柄,后续调用无需再传 lookup.findVirtual(Person.class, "getName", targetMethodType).bindTo(person), interfaceMethodType); GetterFunction getterFunction = (GetterFunction) site.getTarget().invokeExact(person); // 调用静态统计方法 invoke(getterFunction); } // 改为静态方法,让main可以直接调用 static void invoke(GetterFunction getterFunction){ long startTime = System.currentTimeMillis(); for(int i= 0 ; i<3 ; i++){ getterFunction.invoke(); } long endTime = System.currentTimeMillis(); System.out.println("方法执行时间:"+ (endTime - startTime) + "ms"); } @FunctionalInterface interface GetterFunction { // 已绑定Person实例,无需参数,返回void void invoke(); } static class Person { String name; public Person(String name) { this.name = name; } public String getName() { return name; } } }
方案二:让GetterFunction接收Person参数
适合需要复用lambda调用不同Person实例的场景:
public class MyMain { public static void main(String[] args) throws Throwable { Person person = new Person("Bob"); final MethodHandles.Lookup lookup = MethodHandles.lookup(); // 函数式接口方法的类型:接收Person实例,返回String MethodType interfaceMethodType = MethodType.methodType(String.class, Person.class); // 目标方法getName的类型:无参数,返回String(实例方法的接收者会自动作为第一个参数) MethodType targetMethodType = MethodType.methodType(String.class); final CallSite site = LambdaMetafactory.metafactory( lookup, "invoke", MethodType.methodType(GetterFunction.class), interfaceMethodType, lookup.findVirtual(Person.class, "getName", targetMethodType), interfaceMethodType); GetterFunction getterFunction = (GetterFunction) site.getTarget().invokeExact(); invoke(getterFunction, person); } static void invoke(GetterFunction getterFunction, Person person){ long startTime = System.currentTimeMillis(); for(int i= 0 ; i<3 ; i++){ getterFunction.invoke(person); } long endTime = System.currentTimeMillis(); System.out.println("方法执行时间:"+ (endTime - startTime) + "ms"); } @FunctionalInterface interface GetterFunction { // 接收Person实例,返回String,与getName的行为匹配 String invoke(Person person); } static class Person { String name; public Person(String name) { this.name = name; } public String getName() { return name; } } }
关键修复说明
- 签名匹配:确保函数式接口的方法签名与目标方法适配,要么绑定实例让接口方法无参数,要么让接口方法接收实例参数。
- Lambda参数调整:正确指定工厂方法类型、接口方法类型,保证LambdaMetafactory能生成合法的实现类。
- 基础错误修正:修复API拼写、静态方法调用、语法括号等问题。
内容的提问来源于stack exchange,提问作者enthusiast
相关产品推荐
相关产品推荐

