Java:没有默认构造函数的类的newInstance

Ger*_*anK 39 java reflection constructor instance new-operator

我正在尝试为学生的作业构建一个自动测试框架(基于jUnit,但这并不重要).他们必须为某些类创建构造函数,并为它们添加一些方法.后来,通过我提供的测试功能,他们将检查它们是否正常.

我想做的是,通过反射,创建一个我想要测试的类的新实例.问题是,有时候,没有默认的构造函数.我不关心这个,我想创建一个实例并自己初始化实例变量.有没有办法做到这一点?我很抱歉,如果之前有人问过,但我找不到任何答案.

提前致谢.

Jon*_*eet 51

调用Class.getConstructor()然后Constructor.newInstance()传入适当的参数.示例代码:

import java.lang.reflect.*;

public class Test {

    public Test(int x) {
        System.out.println("Constuctor called! x = " + x);
    }

    // Don't just declare "throws Exception" in real code!
    public static void main(String[] args) throws Exception {
        Class<Test> clazz = Test.class;
        Constructor<Test> ctor = clazz.getConstructor(int.class);
        Test instance = ctor.newInstance(5);           
    }
}
Run Code Online (Sandbox Code Playgroud)

  • @GermanK:然后使用Class.getConstructors(),看看有什么可用.你有*依赖于一个实现来实例化一个类.如果你创建一个实例而没有使用适当的参数调用它们的构造函数之一,那么你就不能公平地对它们的类​​进行公平的操作,这会使*期望*被正确地实例化.我建议你*授权*一个特殊的签名. (4认同)
  • 它将涉及一些混乱的反射,以获得一个构造函数,并走它,为每个参数赋予适当的值... (2认同)

Vla*_*lad 6

这是一个通用的解决方案,不需要javassist或其他字节码"操纵器".虽然,它假设构造函数除了简单地将参数分配给相应的字段之外没有做任何其他事情,因此它只选择第一个构造函数并创建一个具有默认值的实例(即0表示int,null表示Object等).

private <T> T instantiate(Class<T> cls, Map<String, ? extends Object> args) throws Exception
{
    // Create instance of the given class
    final Constructor<T> constr = (Constructor<T>) cls.getConstructors()[0];
    final List<Object> params = new ArrayList<Object>();
    for (Class<?> pType : constr.getParameterTypes())
    {
        params.add((pType.isPrimitive()) ? ClassUtils.primitiveToWrapper(pType).newInstance() : null);
    }
    final T instance = constr.newInstance(params.toArray());

    // Set separate fields
    for (Map.Entry<String, ? extends Object> arg : args.entrySet()) {
        Field f = cls.getDeclaredField(arg.getKey());
        f.setAccessible(true);
        f.set(instance, arg.getValue());
    }

    return instance;
}
Run Code Online (Sandbox Code Playgroud)

PS适用于Java 1.5+.该解决方案还假设没有可能阻止调用的SecurityManager管理器f.setAccessible(true).