【问题标题】:Creating an instance using the class name and calling constructor使用类名创建实例并调用构造函数
【发布时间】:2011-08-30 23:25:40
【问题描述】:

有没有办法在给定类名(动态)的情况下创建特定类的实例并将参数传递给它的构造函数。

类似:

Object object = createInstance("mypackage.MyClass","MyAttributeValue");

其中"MyAttributeValue"MyClass 的构造函数的参数。

【问题讨论】:

    标签: java reflection instantiation


    【解决方案1】:

    是的,类似:

    Class<?> clazz = Class.forName(className);
    Constructor<?> ctor = clazz.getConstructor(String.class);
    Object object = ctor.newInstance(new Object[] { ctorArgument });
    

    这当然只适用于单个字符串参数,但你可以很容易地修改它。

    请注意,类名必须是完全限定的,即包括命名空间。对于嵌套类,您需要使用美元(因为这是编译器使用的)。例如:

    package foo;
    
    public class Outer
    {
        public static class Nested {}
    }
    

    要为此获取Class 对象,您需要Class.forName("foo.Outer$Nested")

    【讨论】:

    • newInstance() 是一个可变参数方法(就像GetConstructor()),不需要显式创建Object-array。
    • @Joachim:我知道它是可变参数,但是当你有一个 Object[] 参数时它会变得很棘手,我更喜欢在这种情况下显式创建数组。
    • clazz.getConstructor(String.class);为什么这里是 String.class?
    • @Neutralizer:是的,但我在回答一个不需要动态的问题。
    • @JonSkeet 我知道你来自哪里,但它并不是那么简单 - 我确实看过文档但很困惑,但如果我测试它并且它有效 - 好的然后它有效 -但是如果它不起作用,那么我将不确定问题是否是由于缺少配置或我的某些原因 - 通常在提出如此简单的问题时,人们会抛出真正有帮助的有用花絮。这就是为什么一个简单的“是的,如果你这样做的话”或“不,没有办法”,真的很有帮助。但我现在的理解是没有办法
    【解决方案2】:

    您可以使用Class.forName() 获取所需类的Class 对象。

    然后使用getConstructor() 找到所需的Constructor 对象。

    最后,在该对象上调用 newInstance() 以获取您的新实例。

    Class<?> c = Class.forName("mypackage.MyClass");
    Constructor<?> cons = c.getConstructor(String.class);
    Object object = cons.newInstance("MyAttributeValue");
    

    【讨论】:

      【解决方案3】:

      你可以使用反射

      return Class.forName(className).getConstructor(String.class).newInstance(arg);
      

      【讨论】:

      • 如果使用默认构造函数,删除 String.class 参数值,例如return Class.forName(className).getConstructor().newInstance(arg);
      • @VijayKumar 我想你的意思是Class.forName(className).getConstructor().newInstance(); ;)
      【解决方案4】:

      如果类只有一个空构造函数(如Activity或Fragment等,android类):

      Class<?> myClass = Class.forName("com.example.MyClass");    
      Constructor<?> constructor = myClass.getConstructors()[0];
      

      【讨论】:

      • 这对我有帮助。 Constructor&lt;?&gt; ctor = clazz.getConstructor(String.class) 似乎对我不起作用。
      【解决方案5】:

      当使用(即)getConstructor(String.lang) 时,必须将构造函数声明为 public。 否则会抛出 NoSuchMethodException

      如果您想访问 非公共构造函数,则必须改用(即)getDeclaredConstructor(String.lang)

      【讨论】:

        【解决方案6】:
        【解决方案7】:

        使用 Class&lt;?&gt; 并传递构造函数参数在 Java 中创建对象的非常简单的方法:

        案例 1:- 这是Main 类中的一个小代码:

        import java.lang.reflect.Constructor;
        import java.lang.reflect.InvocationTargetException;
        
        public class Main {
        
            public static void main(String args[]) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        
                // Get class name as string.
                String myClassName = Base.class.getName();
                // Create class of type Base.
                Class<?> myClass = Class.forName(myClassName);
                // Create constructor call with argument types.
                Constructor<?> ctr = myClass.getConstructor(String.class);
                // Finally create object of type Base and pass data to constructor.
                String arg1 = "My User Data";
                Object object = ctr.newInstance(new Object[] { arg1 });
                // Type-cast and access the data from class Base.
                Base base = (Base)object;
                System.out.println(base.data);
            }
        
        }
        

        还有,这是Base 类结构:

        public class Base {
        
            public String data = null;
        
            public Base() 
            {
                data = "default";
                System.out.println("Base()");
            }
        
            public Base(String arg1) {
                data = arg1;
                System.out.println("Base("+arg1+")");
            }
        
        }
        

        案例 2:- 您可以为具有多个参数的构造函数和复制构造函数进行类似的编码。例如,将 3 个参数作为参数传递给 Base 构造函数将需要在类中创建构造函数,并将上面的代码更改为:

        Constructor<?> ctr = myClass.getConstructor(String.class, String.class, String.class);
        Object object = ctr.newInstance(new Object[] { "Arg1", "Arg2", "Arg3" }); 
        

        这里的 Base 类应该是这样的:

        public class Base {
        
            public Base(String a, String b, String c){
                // This constructor need to be created in this case.
            }   
        }
        

        注意:- 不要忘记处理代码中需要处理的各种异常。

        【讨论】:

        • 另一种方式也是通过clone()现有的java对象。这将创建现有 Java 对象的副本。对于这种情况,您还必须处理深拷贝或浅拷贝概念。
        【解决方案8】:

        如果有人正在寻找一种方法来创建一个类的实例,尽管该类遵循单例模式,这里有一种方法。

        // Get Class instance
        Class<?> clazz = Class.forName("myPackage.MyClass");
        
        // Get the private constructor.
        Constructor<?> cons = clazz.getDeclaredConstructor();
        
        // Since it is private, make it accessible.
        cons.setAccessible(true);
        
        // Create new object. 
        Object obj = cons.newInstance();
        

        这仅适用于使用私有构造函数实现单例模式的类。

        【讨论】:

          【解决方案9】:

          另一个有用的答案。 How do I use getConstructor(params).newInstance(args)?

          return Class.forName(**complete classname**)
              .getConstructor(**here pass parameters passed in constructor**)
              .newInstance(**here pass arguments**);
          

          在我的例子中,我的类的构造函数将 Webdriver 作为参数,所以在下面的代码中使用:

          return Class.forName("com.page.BillablePage")
              .getConstructor(WebDriver.class)
              .newInstance(this.driver);
          

          【讨论】:

            【解决方案10】:

            您还可以在创建的对象中调用方法。

            您可以通过调用第一个构造器来立即创建对象,然后在创建的对象中调用第一个方法。

                Class<?> c = Class.forName("mypackage.MyClass");
                Constructor<?> ctor = c.getConstructors()[0];
                Object object=ctor.newInstance(new Object[]{"ContstractorArgs"});
                c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs);
            

            【讨论】:

            • 你怎么知道第一个构造函数接受String作为参数?更改构造函数顺序时变得有点混乱
            • 课程文档中的@Farid
            • 我猜还是getConstructor(ClassName.class) 更好。即使类中构造函数的顺序发生变化,也无需手动查找位置
            • @Farid - c.getDeclaredMethods()[0].invoke(object,Object... MethodArgs);指定特殊的构造函数在某些情况下你可能需要这个;但你是对的。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2016-03-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多