如何通过传递Object []而不是带反射的参数列表来创建类的新实例

时间:2015-11-18 08:11:37

标签: java reflection constructor

您对如何编写此类方法有任何线索吗?

public abstract class AbstractClass{}

public class TrialClass extends AbstractClass{
    public TrialClass(final String a, final String b){}
    public TrialClass(final String a, final String b, final String c){}
}

public class getNewInstance(final Class<? extends AbstractClass> clazz, Object... constructorParameters){
    //???
}

TrialClass trialClass = getNewInstance(TrialClass.class, "A", "B");

2 个答案:

答案 0 :(得分:3)

可能更灵活的方法是检查所有构造函数并找到兼容的构造函数:

public static <T> T getNewInstance(final Class<T> clazz, Object... constructorParameters) throws InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
    Constructor<?> candidate = null;
    for(Constructor<?> constructor : clazz.getConstructors()) {
        if(Modifier.isPublic(constructor.getModifiers()) && isConstructorCompatible(constructor, constructorParameters)) {
            if(candidate == null)
                candidate = constructor;
            else
                throw new IllegalArgumentException("Several constructors found which are compatible with given arguments");
        }
    }
    if(candidate == null)
        throw new IllegalArgumentException("No constructor found which is compatible with given arguments");
    return (T) candidate.newInstance(constructorParameters);
}

private static boolean isConstructorCompatible(Constructor<?> constructor, Object[] constructorParameters) {
    Class<?>[] parameterTypes = constructor.getParameterTypes();
    if(parameterTypes.length != constructorParameters.length)
        return false;
    for(int i=0; i<parameterTypes.length; i++)
        if(!isParameterCompatible(parameterTypes[i], constructorParameters[i]))
            return false;
    return true;
}

private static boolean isParameterCompatible(Class<?> type, Object parameter) {
    if(parameter == null)
        return !type.isPrimitive();
    if(type.isInstance(parameter))
        return true;
    if(type.isPrimitive()) {
        if (type == int.class && parameter instanceof Integer
                || type == char.class && parameter instanceof Character
                || type == byte.class && parameter instanceof Byte
                || type == short.class && parameter instanceof Short
                || type == long.class && parameter instanceof Long
                || type == float.class && parameter instanceof Float
                || type == double.class && parameter instanceof Double
                || type == boolean.class && parameter instanceof Boolean)
            return true;
    }
    return false;
}

虽然像varargs-constructors一样仍有未解决的问题。同样歧义的情况也不会像javac那样解决(例如,如果你有MyObj(Object)MyObj(String)构造函数,你将无法使用后者,两者都匹配)。

答案 1 :(得分:2)

Class方法包含getConstructor方法,该方法将Class数组作为参数,对应于构造函数参数。您必须从参数数组构建此数组。

类似的东西:

public <T> T getNewInstance(final Class<T> clazz, Object... constructorParameters) throws InstantiationException, IllegalAccessException, InvocationTargetException, SecurityException, NoSuchMethodException{
    Class[] parameterTypes = new Class[constructorParameters.length];
    for(int i = 0; i < constructorParameters.length; i++) {
        parameterTypes[i] = constructorParameters[i].getClass();
    }

    Constructor<T> constructor = clazz.getConstructor(parameterTypes);
    return constructor.newInstance(constructorParameters);
}

编辑:正如Codebender所说,当子类型作为参数传递时,这不起作用。