Javareflection调用与原始types的构造函数
我在我的testing框架中有一个方法,根据传入的参数创build一个类的实例:
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(); } }
问题是,如果构造函数具有原始types,则不起作用,如下所示:
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)
原始整数是自动装箱的对象版本,但我怎么让他们回来调用构造函数?
使用Integer.TYPE
而不是Integer.class
。
根据Javadocs ,这是“代表基本typesint
的Class实例”。
你也可以使用int.class
。 这是Integer.TYPE
的一个快捷方式。 不仅是类,即使对于原始types,你也可以在Java中声明type.class
。
要引用基本types使用,例如:
Integer.TYPE;
您将需要知道哪些参数传入您的方法是原始值。 你可以这样做:
object.getClass().isPrimitive()
由于原始types是自动复制的,因此getConstructor(java.lang.Class<?>... parameterTypes)
调用将失败。 您将需要手动循环通过可用的构造函数。 如果所有types匹配,那么你很好。 如果某些types不匹配,但所需的types是基本的,并且可用types是相应的包装类,那么可以使用该构造函数。 见下图:
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)); }
你可以写
int[].class.getComponentType()
要么
Integer.TYPE
要么
int.class
如果将原始的int
值自动装入到Integer
对象中,则不再是原始的。 你不能从Integer
实例中知道它是否是int
。
我build议将两个数组传入test
方法:一个使用types,另一个使用值。 如果你有一个构造函数MyClass(Object)
和传递string值( getConstructor
会寻找String
构造函数),它也会消除歧义。
此外,如果参数值为空,则无法告知预期的参数types。