You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用LambdaMetaFactory获取类方法执行时间?遇AbstractMethodError异常

问题根源

  1. 函数式接口签名不兼容:GetterFunction的invoke()是无参数无返回值,但目标方法Person.getName()是无参数返回String,两者签名不匹配,LambdaMetafactory无法生成正确实现该接口的类,最终抛出AbstractMethodError。
  2. LambdaMetafactory参数错误:
    • 工厂方法类型(第三个参数)未正确指定,没有考虑到Person实例作为方法接收者的需求。
    • 函数式接口方法类型与目标方法类型不匹配,导致lambda生成逻辑混乱。
  3. 缺失方法接收者:Person.getName()是实例方法,必须传入Person实例才能调用,当前代码未提供任何实例。
  4. 语法与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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 20:42:13