Java反射调用具有原始类型的构造函数

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3925587/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-14 07:01:02  来源:igfitidea点击:

Java Reflection calling constructor with primitive types

javareflection

提问by Steve

I have a method in my test framework that creates an instance of a class, depending on the parameters passed in:

我的测试框架中有一个方法可以根据传入的参数创建一个类的实例:

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();
    }
}

The problem is, this doesn't work if the constructor has primitive types, as follows:

问题是,如果构造函数具有原始类型,这将不起作用,如下所示:

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

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

Results in:

结果是:

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

The primitive ints are auto-boxed in to object versions, but how do I get them back for calling the constructor?

原始整数被自动装箱到对象版本中,但是如何将它们取回以调用构造函数?

采纳答案by Andrzej Doyle

Use Integer.TYPEinstead of Integer.class.

使用Integer.TYPE代替Integer.class

As per the Javadocs, this is "The Class instance representing the primitive type int."

根据Javadocs,这是“代表原始类型的 Class 实例int”。

You can also use int.class. It's a shortcut for Integer.TYPE. Not only classes, even for primitive types you can say type.classin Java.

您也可以使用int.class. 这是 的捷径Integer.TYPE。不仅是类,甚至对于type.classJava 中的原始类型也是如此。

回答by Plaudit Design

To reference primitive types use, for example:

要引用原始类型,请使用,例如:

Integer.TYPE;

You will need to know which arguments passed into your method are primitive values. You can do this with:

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

object.getClass().isPrimitive()

回答by Nikita Rybak

If primitive intvalue is autoboxed into Integerobject, it's not primitive anymore. You can't tell from Integerinstance whether it was intat some point.

如果原始int值被自动装箱到Integer对象中,则它不再是原始值。你无法从Integer实例中判断它是否int在某个时候。

I would suggest passing two arrays into testmethod: one with types and another with values. It'll also remove ambiguity if you have a constructor MyClass(Object)and pass string value (getConstructorwould be looking for Stringconstructor).
Also, you can't tell expected parameter type if parameter value is null.

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

回答by Jake

Since the primitive types are autoboxed, the getConstructor(java.lang.Class<?>... parameterTypes)call will fail. You will need to manually loop through the available constructors. If all types match then you're fine. If some types do not match, but the required type is a primitive AND the available type is the corresponding wrapper class, then you can use that constructor. See bellow:

由于原始类型是自动装箱的,因此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));
}

回答by user3896501

you can write

你可以写

int[].class.getComponentType()

or

或者

Integer.TYPE

or

或者

int.class

回答by Spektakulatius

To actually check if a type is a primitive or it's wrapper use:

要实际检查类型是原始类型还是包装器,请使用:

ClassUtils.isPrimitiveOrWrapper(memberClazz)

In the case you want to check if it's a specific type take a look at this:

如果您想检查它是否是特定类型,请查看以下内容:

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

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

In any case @Andrzej Doyle was completely right!

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