首页 > 解决方案 > 如何使用反射调用在可变参数中包含 null 的方法

问题描述

我的情况就像一个类包含相同的方法名称,我们正在尝试使用反射来调用,但是当其中一个参数包含 null 时似乎有问题

例如 :


package test;

public class Invoker {
    public void test(String a, Integer b) {
        System.out.println("String, Integer");
    }

    public void test(Integer a, Integer b) {
        System.out.println("Integer, Integer");
    }

    public void invoke(String methodName, Object ...args) {
        try {
           Class<?>[] clazz = new Class[args.length];
            int i=0;
           for(Object a:args) {
               clazz[i++] = a != null ? a.getClass() : null;
           }

           Method m = this.getClass().getMethod(methodName, clazz);

           // ... Continue for invocation

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String ...args) {
        Invoker invoker = new Invoker();

        // happened to be null sometimes
        String a = null;
        Integer b = 123;

        System.out.println("Trigger Normally");
        invoker.test(a, b);

        System.out.println("Trigger via Reflection");
        invoker.invoke("test", a, b);
    }
}

结果

Trigger Normally
String, Integer
Trigger via Reflection
java.lang.NoSuchMethodException: test.Invoker.test(null, java.lang.Integer)
    at java.lang.Class.getMethod(Class.java:1678)
    at test.Invoker.invoke(Invoker.java:21)
    at test.Invoker.main(Invoker.java:42)

Argument 有时恰好为 null,但如果为 null,则会触发NoSuchMethodException

我们的方法名不是唯一的,它必须是重载结构。

标签: javareflection

解决方案


由于早期绑定,被调用的重载方法是在编译时确定的(或者如果无法确定,则会出现编译时错误)。既然你有String a = null,编译器就可以确定你要调用test(String, Integer)

您的反射调用发生在运行时并且缺少null参数中的类型信息(该方法不知道它来自 a String a,编译器在编译时知道,但这是运行时),因此您需要提供信息是否为 nullStringInteger

如果您想让反射方法使用空值(和重载方法),则需要添加一个单独的类型参数以在空值的情况下使用。例如

invoker.invoke("test", a, String.class, b, Integer.class);

如果没有额外的类型信息,你不能让它为空值工作,因为它就像调用test(null, 1). 在这种情况下,编译器也需要您的帮助,例如,test((Integer)null, 1)或者test((String)null, 1),尝试一下。


推荐阅读