Java Reflection用原始类型调用构造函数

时间:2010-10-13 15:56:52

标签: java reflection

我的测试框架中有一个方法,它创建一个类的实例,具体取决于传入的参数:

public void test(Object... constructorArgs) throws Exception {
    Constructor<T> con;
    if (constructorArgs.length > 0) {
        Class<?>[] parameterTypes = new Class<?>[constructorArgs.length];
        for (int i = 0; i < constructorArgs.length; i++) {
            parameterTypes[i] = constructorArgs[i].getClass();  
        }
        con = clazz.getConstructor(parameterTypes);
    } else {
        con = clazz.getConstructor();
    }
}

问题是,如果构造函数具有基本类型,则不起作用,如下所示:

public Range(String name, int lowerBound, int upperBound) { ... }

.test("a", 1, 3);

结果:

java.lang.NoSuchMethodException: Range.<init>(java.lang.String, java.lang.Integer, java.lang.Integer)

原始int是自动装入对象版本的,但是如何让它们返回以调用构造函数?

6 个答案:

答案 0 :(得分:136)

使用Integer.TYPE代替Integer.class

根据Javadocs,这是“表示基本类型int的类实例。”

您也可以使用int.class。这是Integer.TYPE的捷径。不仅是类,甚至是原始类型,你可以在Java中说type.class

答案 1 :(得分:19)

要引用基元类型,请使用,例如:

Integer.TYPE;

您需要知道传递给方法的参数是原始值。你可以这样做:

object.getClass().isPrimitive()

答案 2 :(得分:6)

由于原始类型是自动装箱的,getConstructor(java.lang.Class<?>... parameterTypes)调用将失败。您需要手动遍历可用的构造函数。如果所有类型匹配那么你就没事了。如果某些类型不匹配,但所需类型是基元,并且可用类型是相应的包装类,则可以使用该构造函数。见下文:

static <C> Constructor<C> getAppropriateConstructor(Class<C> c, Object[] initArgs){
    if(initArgs == null)
        initArgs = new Object[0];
    for(Constructor con : c.getDeclaredConstructors()){
        Class[] types = con.getParameterTypes();
        if(types.length!=initArgs.length)
            continue;
        boolean match = true;
        for(int i = 0; i < types.length; i++){
            Class need = types[i], got = initArgs[i].getClass();
            if(!need.isAssignableFrom(got)){
                if(need.isPrimitive()){
                    match = (int.class.equals(need) && Integer.class.equals(got))
                    || (long.class.equals(need) && Long.class.equals(got))
                    || (char.class.equals(need) && Character.class.equals(got))
                    || (short.class.equals(need) && Short.class.equals(got))
                    || (boolean.class.equals(need) && Boolean.class.equals(got))
                    || (byte.class.equals(need) && Byte.class.equals(got));
                }else{
                    match = false;
                }
            }
            if(!match)
                break;
        }
        if(match)
            return con;
    }
    throw new IllegalArgumentException("Cannot find an appropriate constructor for class " + c + " and arguments " + Arrays.toString(initArgs));
}

答案 3 :(得分:3)

你可以写

int[].class.getComponentType()

Integer.TYPE

int.class

答案 4 :(得分:2)

如果将原始int值自动装箱到Integer对象中,则它不再是原始值。您无法在Integer个实例中告诉它在某个时刻是否为int

我建议将两个数组传递给test方法:一个包含类型,另一个包含值。如果你有一个构造函数MyClass(Object)并且传递字符串值(getConstructor将寻找String构造函数),它也会消除歧义。 此外,如果参数值为null,则无法告知预期的参数类型。

答案 5 :(得分:0)

要实际检查类型是基本类型还是包装类型,请使用:

wp_verify_nonce( $nonce, 'my-nonce' );

如果要检查是否为特定类型,请查看以下内容:

https://stackoverflow.com/a/27400967/2739334

无论如何,@ Andrzej Doyle完全正确!