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

使用MethodHandlers.lookup().findStatic抛出NoSuchMethodException问题排查

MethodHandles调用静态void方法抛出NoSuchMethodException的解决方法

问题场景

使用Java MethodHandlers API调用修改状态的静态void方法时抛出NoSuchMethodException,但通过Reflection API的getMethod可以正常调用目标方法。

代码示例

class Main {
    public static void main(String[] args) throws Throwable {

        System.out.println("Times before: " + Foobar.getTimes());
        final Class<?> aClass = MethodHandles.lookup().findClass(Foobar.class.getName());

        incReflectionApi(aClass);
        incMethodHandler(aClass);

    }

    private static void incReflectionApi(Class<?> aClass) throws Throwable {
        final Method init = aClass.getMethod("increment", (Class<?>[]) null);
        init.invoke(null, (Object[]) null);

        System.out.println("Reflection api: " + Foobar.getTimes());
    }

    private static void incMethodHandler(Class<?> aClass) throws Throwable {

        // 此处抛出异常
        final MethodHandle handle = MethodHandles.lookup().findStatic(aClass, "increment", MethodType.methodType(Void.class));
        handle.invoke();

        System.out.println("MethodHandler api: " + Foobar.getTimes());
    }

    public static class Foobar {

        private static int times;

        public static void increment() {
            times++;
        }

        public static int getTimes() {
            return times;
        }
    }
}

报错信息

Times before: 0
Reflection api: 1
Exception in thread "main" java.lang.NoSuchMethodException: no such method: Main$Foobar.increment()Void/invokeStatic
    at java.base/java.lang.invoke.MemberName.makeAccessException(MemberName.java:963)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1101)
    at java.base/java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:2030)
    at java.base/java.lang.invoke.MethodHandles$Lookup.findStatic(MethodHandles.java:1102)
    at Main.incMethodHandler(scratch_5.java:26)
    at Main.main(scratch_5.java:14)
Caused by: java.lang.NoSuchMethodError: 'java.lang.Void Main$Foobar.increment()'
    at java.base/java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.base/java.lang.invoke.MemberName$Factory.resolve(MemberName.java:1070)
    at java.base/java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1098)
    ... 4 more

问题原因

核心错误在于指定方法返回类型时混淆了void.class和Void.class:

  • 目标方法increment是void返回值(基本类型的无返回值)
  • 代码中用MethodType.methodType(Void.class)指定返回类型,Void.class是包装类,对应引用类型,和原方法的返回类型不匹配
  • Reflection API的getMethod不把返回类型作为方法查找的条件,只根据方法名和参数列表匹配,所以可以正常找到方法;但MethodHandles的findStatic需要精确匹配方法的完整类型(包括返回值),因此会抛出找不到方法的异常

解决方案

将MethodType.methodType(Void.class)替换为MethodType.methodType(void.class),修改后的incMethodHandler方法如下:

private static void incMethodHandler(Class<?> aClass) throws Throwable {
    // 使用void.class匹配无返回值方法
    final MethodHandle handle = MethodHandles.lookup().findStatic(aClass, "increment", MethodType.methodType(void.class));
    handle.invoke();

    System.out.println("MethodHandler api: " + Foobar.getTimes());
}

修改后运行代码,MethodHandlers API就能正常调用increment方法,输出结果会显示MethodHandler api: 2,符合预期。

内容的提问来源于stack exchange,提问作者Toerktumlare

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 19:27:17