在Java中使用反射来设置方法的参数

时间:2019-04-29 22:59:17

标签: java reflection

我正在努力实现与以下近似的东西:

public class MyClass<E>
{
    protected MyClass(Object[] variables)
    {
        //init
    }

    public MyClass(Comparator<? super E> comp, Object[] variables)
    {
        //init
    }

    public static <K extends Comparable<? super K>, T extends MyClass<K>> 
         T construct(T example, Object[] variables)
    {
        return new T(variables);
    }
}

在Object []变量不是实际代码的地方,而是占位符(无论构造的实际参数是什么)。

这是我的问题。我已经看到了无数个示例,无论有无反射,当T的构造函数的参数提前已知并且可以在构造的参数中指定时,该如何做。但是,即使T的构造函数的参数未知,我也希望能够做到这一点。有没有办法做到这一点?

只要解决方案有效,我都不在乎该解决方案是否使用反射,但是反射似乎是最可能的选择。

从整体上来说,我还是一个新手,如果这个问题很基础,我深表歉意。

编辑: 由于反馈,无法动态设置construct()的参数,我想稍作更改。

假定受保护的构造函数具有构造类所需的参数,如果我使用vararg (public static <K extends Comparable<? super K>, T extends MyClass<K>> T construct(T example, Object... variables)),那么确保传递给变量的参数与构造函数所需的参数匹配的最佳方法是什么?我希望动态地执行此操作,因为这样编译器本身可以避免此类问题,但是如果没有这种可能性,我会寻求最佳的替代解决方案。

编辑:为澄清起见,这是我的实际目标:我希望MyClass接受或者参数化E,它扩展了Comparable 任何参数化,但是具有比较器我可以简单地通过构造函数来实现第二个目标,但是为了使E在第二种情况下对任何选项保持打开状态,我必须使它对所有选项都保持打开状态。为了解决这个问题,我使通用构造函数受到保护,并制作了一个公共静态方法来强制Comparable实现并充当伪构造函数,返回类型为MyClass,其中K是Comparable。但是,这会在另一个类扩展MyClass时引起问题。如果我事先知道继承的类将具有与MyClass相同的参数,那么我可以简单地隐藏该方法并相应地更改返回类型。但是,如果我想让子类具有不同的参数,那么我已经更改了方法的签名,并且不再可以使用它来隐藏前一个方法,这意味着子类不仅可以返回自身的实例,还可以返回一个实例。其父实例完全不同。这就是我想避免的。

3 个答案:

答案 0 :(得分:0)

这可能有效,但我不建议这样做。 请注意,为使此功能example有效,并且variables的所有成员都不得null

public static <K extends Comparable<? super K>, T extends MyClass<K>> 
     T construct(T example, Object[] variables) throws 
                 NoSuchMethodException,
                 SecurityException,
                 InstantiationException,
                 IllegalAccessException,
                 IllegalArgumentException,
                 InvocationTargetException 
{
    Objects.requireNotNull(example);

    Class<?>[] argTypes = new Class<?>[variables.length];
    for ( int i = 0; i < variables.length; ++i)
    {
        // This will NPE if variables[i] is null
        argTypes[i] = variables[i].getClass();
    }

    // This will throw, if constructor is not defined
    Constructor<?> constructor = example.getClass().getConstructor(argTypes);

    return (T) constructor.newInstance(variables);
}

通常,您正在做什么,可以通过创建一个创建特定类实例的Factory接口来实现。

答案 1 :(得分:0)

我认为您不需要反思。您只需要简化所需的内容,并使用Java和泛型的功能来满足您的需求。这是根据您的第三次编辑的示例:

class MyClass<E> {
    private Comparator<MyClass<E>> comparator;

    public MyClass(List<Object> params, Comparator<MyClass<E>> comparator) {
        //init
        this.comparator = comparator;
    }

}
class  MyClassExtension extends MyClass<Integer> {

    public MyClassExtension(List<Object> params, Comparator<MyClass<java.lang.Integer>> comparator) {
        super(params, comparator);
    }
}
class  MyClassExtension2<E> extends MyClass<E> {

    public MyClassExtension2(List<Object> params, Comparator<MyClass<E>> comparator) {
        super(params, comparator);
    }
}

答案 2 :(得分:0)

我想我可能已经实现了一个潜在的解决方案,尽管我希望它的可行性得到反馈。

public class MyClass<E>
{
    public MyClass(Comparable<? super E> example, E example2, Object[] variables) 
      throws IllegalArgumentException
    {
        if(!example.getClass().equals(example2.getClass())
        {
             throw new IllegalArgumentException();
        }
        //init
    }

    public MyClass(Comparator<? super E> comp, Object[] variables)
    {
        //init
    }
}

这个想法是if语句强制example与通用E属于同一类,而example作为参数的存在迫使该类实现Comparable。