【问题标题】:How to create instance with a constructor chosen by the user?如何使用用户选择的构造函数创建实例?
【发布时间】:2011-05-04 22:41:16
【问题描述】:

我一直在努力更好地理解 Java 的反射工具,现在我正在尝试使用用户在下拉框中选择的构造函数创建一个类的新实例。

  //ask user what to name the new instance of chosen Class ( passed into this method )
            String instanceName = JOptionPane.showInputDialog(null, "Under what name would you like to store this Instance?", 
                    "Create an Instance of a Class", JOptionPane.QUESTION_MESSAGE);

            Object chosenC = JOptionPane.showInputDialog(null, "Please choose a Constructor for" + chosenClass, 
                    "Create an Instance of a Class", 3, null, getConstructors(chosenClass), JOptionPane.QUESTION_MESSAGE);

            Constructor c = (Constructor)chosenC;
            Class[] params = c.getParameterTypes(); //get the parameters of the chosen Constructor


    try {

            //create the instance with the correct constructor
            instance = c.newInstance((Object[])params); 

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e){
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } 

现在,如果我选择除默认构造函数(无参数)以外的任何内容,我会收到 ArgumentTypeMismatch 异常。我是否遗漏了一些明显的东西?

感谢您的帮助。

编辑 谢谢大家的答案。

但是那我要如何要求参数呢?如果我得到 params 数组的长度,那么我必须确定每个索引是什么类型的类,并要求用户以正确的形式输入一个值?那么我如何将这个新数组传递给 newInstance 参数呢?

【问题讨论】:

  • 通常这种动态对象创建最好使用具有默认构造函数的类来完成。这样你就可以创建一个对象,然后通过设置器等设置你想要的任何参数。在这种情况下,需要循环所有 params 并为每个类创建 clazz.newInstance(...)... 这可能是美好的无限深渊
  • 我明白了。谢谢哈。这是有道理的。
  • @Frank71 - 这是面向开发人员的应用程序,还是您有最终用户?如果是后者,我不会将其留给反射 API 来确定行为,而是会在代码中从下拉框中指定每个选项的构造函数/行为。

标签: java reflection


【解决方案1】:

给定一个具有如下构造函数的类:

MyClass(String s, Long l)

您的代码实际上调用了以下内容:

new MyClass(String.class, Long.class)

它应该在哪里调用:

new MyClass("", 1L)

您需要每个构造函数参数类型的实例,但您只是传递类。有趣的是,如果你的构造函数只接受Class 的实例,它会起作用,但会产生意想不到的结果。

【讨论】:

  • 很好的例子。但我不得不对最后一句话提出质疑。它会编译,但它可能不是任何人想要的,所以说“它会工作”不太准确,我认为。
【解决方案2】:

当您需要一个实例数组时,您将 Class[] 传递给构造函数。例如,如果你的构造函数是 Foo(String),你想做一些类似

c.newInstance(new Object[] {"aString"});

你正在做的是,

c.newInstance(new Object[] {String.class});

【讨论】:

    【解决方案3】:

    您的params 需要是传递给构造函数的参数。您的参数都是类引用,因此除非您的所有参数都是Class a, Class b, Class c,否则这是行不通的。

    也许您应该允许用户确定值应该是什么。

    【讨论】:

      【解决方案4】:

      调用:

      instance = c.newInstance((Object[])params); 
      

      这里你必须传入构造函数的参数,而不是你通过调用获得的类型:

      Class[] params = c.getParameterTypes();
      

      如果你的构造函数是:

      public MyConstructor( int foo, String bar ) {
      //...
      }
      

      那么您应该将参数传递为(例如):

      Object [] params = new Object [] { 10, "someString" };
      

      【讨论】:

        【解决方案5】:

        在构造函数实例上调用newInstance 时,需要传递正确类的参数。您将 Class 对象本身作为参数提供。

        例如,如果你的构造函数是

        Person(String firstName, String lastName)
        

        你会打电话

        new Person("John", "Doe");
        

        或者,在反射方面

        c.newInstance("John", "Doe");
        

        但你的代码实际上正在做

        c.newInstance(String.class, String.class);
        

        如果您希望用户选择构造函数,您还需要向他询问一些参数。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-09-25
          • 1970-01-01
          • 2016-03-02
          • 2011-08-30
          • 1970-01-01
          相关资源
          最近更新 更多