Java:如何在Java Reflection中使用非原始类型进行构造函数.newInstance()?

3
在经过一整天的搜索后,我仍然无法弄清楚如何实例化一个自己创建的类的新对象,如果构造函数需要非原始类型的参数。现在我开始怀疑这是否可能!在反射文档中,他们只讨论了原始类型(如int、float、boolean等)。而我找到的所有其他信息/网站/研讨会/示例也只考虑了原始类型来查找构造函数并实例化一个新实例。 所以我想做的是以下内容(分解场景):
假设我有一个名为MyStupidClass的类。另一个类(我们将其命名为MyUsingClass)在构造函数中以MyStupidClass对象作为参数。现在在我的主应用程序中,我希望能够加载MyUsingClass类并从构造函数中实例化一个对象。
这是我到目前为止关于“使用反射”的发现: 使用空构造函数:
//the MyUsingClass:
public class MyUsingClass {

   //the public (empty) constructor
   public MyUsingClass() {
      ...
   }
}

在主应用程序中,我现在会做如下操作:
//get the reflection of the MyUsingClass
Class<?> myUsingClassClass = Class.forName("MyUsingClass");
//get the constructor [I use getConstructor() instead of getConstructors(...) here as I know there is only one]
Constructor<?> myUsingClassConstr = myUsingClassClass.getConstructor();
//instanciate the object through the constructor
Object myInstance = myUsingClassConstr.newInstance(null);

现在,如果我在MyUsingClass中使用一些原始类型,它会看起来像这样:
//the MyUsingClass:
public class MyUsingClass {

   //the public (primitive-only) constructor
   public MyUsingClass(String a, int b) {
      ...
   }
}

在主应用程序中,最后一行将更改为类似以下内容:
//instanciate the object through the constructor
Object myInstance = myUsingClassConstr.newInstance(new Object[]{new String("abc"), new Integer(5)});

到目前为止没有问题(由于这只是一个分解的例子,上面的代码可能有一些小错误...) 现在关键问题是,如果MyUsingClass看起来像这样,我该如何创建myInstance:

//the MyUsingClass:
public class MyUsingClass {

   //the public (primitive-only) constructor
   public MyUsingClass(String a, int b, MyStupidObject toto) {
      ...
   }
}

我需要帮助!非常感谢您阅读我的问题!

问候sv


1
String 不是原始类型。你是否尝试对 MyStupidObject 做与 String 相同的操作? - BalusC
newInstance方法接受一个对象数组作为参数,在JavaDoc API中并没有规定这些参数必须是基本类型的包装类型,只是说会根据需要进行拆包。你尝试过像这样的操作吗:nObject myInstance = myUsingClassConstr.newInstance(new Object[]{new String("abc"), new Integer(5), new MyStupidObject()});?如果尝试了但不起作用,那么抛出了什么异常? - Eric Levine
3个回答

13
没问题,很多年前我也花了很多时间研究这个东西。
  1. 只有在调用默认构造函数时,才能使用 Class.newInstance()
  2. 在所有其他情况下,您必须通过调用 getConstructor() 找到适当的构造函数,然后调用其 newInstance()
  3. 在调用 getConstructor() 时,对于原始类型,请使用 int.classlong.classboolean.class 等。如果您的类 Foo 具有构造函数 Foo(int p),则必须执行以下操作:

    Constructor c = Foo.class.getConstructor(int.class);

  4. 一旦您拥有构造函数,请使用 newInstance() 调用它:

    c.newInstance(12345);

对于多个参数的构造函数,请参考以下示例:

`c.newInstance(new Object[] {12345, "foo", true})`

请注意,自Java 5以来,我们有了自动装箱的运气。对于5之前的版本,我们必须使用更冗长的语法:

`c.newInstance(new Object[] {new Integer(12345), "foo", new Boolean(true)})`

也就是说,我们使用 int.class 来定位构造函数,使用 Integer 类型来调用它。

希望这可以帮助你。


1
请注意,我们也有变量参数的运气 - 无需使用对象数组。 c.newInstance(12345,“foo”,true) - Martin Algesten

1

和其他类型一样,您可以调用构造函数:

Object myInstance = myUsingClassConstr.newInstance(new Object[] {
    new String("abc"),
    new Integer(5),
    new MyStupidObject()
});

来自 Constructor.newInstance文档

使用由此Constructor对象表示的构造函数创建并初始化构造函数声明类的新实例,并使用指定的初始化参数。单个参数会自动解包以匹配原始形式参数,原始和引用参数都必要时受到方法调用转换的影响。

参考类型在此明确列出,不需要特殊处理。


注意 .newInstance(Object... args) 中的可变参数。您可以跳过数组并使用自动装箱来传递 Integer:.newInstance("abc", 5, new MyStupidObject()) - Martin Algesten

0

好的,这些答案都对我很有帮助。现在它正在工作,至少乍一看是这样的。需要进行进一步的测试,但我希望现在能够独立解决这个问题!

非常感谢...

[虽然在规格说明中他们可能会更具体地讨论这个主题]


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接