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。