【问题标题】:Is there a way to instantiate a class by name in Java?有没有办法在 Java 中按名称实例化一个类?
【发布时间】:2020-12-23 10:23:33
【问题描述】:

我正在寻找一个问题:Instantiate a class from its string name,它描述了如何实例化具有名称的类。有没有办法在Java中做到这一点?我将拥有包名和类名,并且我需要能够创建具有该特定名称的对象。

【问题讨论】:

  • 我们实例化一个class,结果是一个object(或:instance )。
  • 答案是肯定的,但我认为你应该问是否这是个好主意。强大的力量(反思)带来了巨大的责任,只有在理解并考虑后果的情况下才应该使用它。

标签: java string object instantiation


【解决方案1】:

使用Class.forName("类的字符串名称").newInstance();

Class.forName("A").newInstance();

这将导致名为 A 的类被初始化。

【讨论】:

    【解决方案2】:
    MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();
    

    【讨论】:

    • 值得一提的是,如果类没有无参数构造函数(并且有其他构造函数),或者无参数构造函数不可访问,这不起作用。
    【解决方案3】:
    String str = (String)Class.forName("java.lang.String").newInstance();
    

    【讨论】:

      【解决方案4】:

      两种方式:

      方法 1 - 仅适用于具有无参数构造函数的类

      如果你的类有一个无参数的构造函数,你可以使用Class.forName() 获取一个Class 对象并使用newInstance() 方法创建一个实例(但要注意这个方法通常是considered evil,因为它可以击败 Java 的已检查异常)。

      例如:

      Class<?> clazz = Class.forName("java.util.Date");
      Object date = clazz.newInstance();
      

      方法二

      如果类没有任何无参数构造函数,另一种更安全的方法是查询您的类对象以获取其Constructor 对象并在此对象上调用newInstance() 方法:

      Class<?> clazz = Class.forName("com.foo.MyClass");
      Constructor<?> constructor = clazz.getConstructor(String.class, Integer.class);
      Object instance = constructor.newInstance("stringparam", 42);
      

      这两种方法都称为reflection。您通常必须捕获​​可能发生的各种异常,包括:

      • JVM 找不到或无法加载您的类
      • 您尝试实例化的类没有正确类型的构造函数
      • 构造函数本身抛出异常
      • 您尝试调用的构造函数不是公开的
      • 已安装安全管理器并正在防止发生反射

      【讨论】:

      • @Simon 你能详细说明/指点一下安全管理器吗?
      【解决方案5】:

      这样的东西应该可以工作......

      String name = "Test2";//Name of the class
              Class myClass = Class.forName(name);
              Object o = myClass.newInstance();
      

      【讨论】:

        【解决方案6】:

        使用 java 反射

        创建新对象 构造函数没有方法调用等价物,因为调用构造函数等价于创建一个新对象(最准确地说,创建一个新对象涉及内存分配和对象构造)。所以与上一个例子最接近的等价物是:

        import java.lang.reflect.*;
        
           public class constructor2 {
              public constructor2()
              {
              }
        
              public constructor2(int a, int b)
              {
                 System.out.println(
                   "a = " + a + " b = " + b);
              }
        
              public static void main(String args[])
              {
                 try {
                   Class cls = Class.forName("constructor2");
                   Class partypes[] = new Class[2];
                    partypes[0] = Integer.TYPE;
                    partypes[1] = Integer.TYPE;
                    Constructor ct 
                      = cls.getConstructor(partypes);
                    Object arglist[] = new Object[2];
                    arglist[0] = new Integer(37);
                    arglist[1] = new Integer(47);
                    Object retobj = ct.newInstance(arglist);
                 }
                 catch (Throwable e) {
                    System.err.println(e);
                 }
              }
           }
        

        它找到一个处理指定参数类型的构造函数并调用它,以创建对象的新实例。这种方法的价值在于它是纯动态的,在执行时而不是在编译时查找和调用构造函数。

        【讨论】:

          【解决方案7】:

          Class.forName("ClassName") 将解决您的目的。

          Class class1 = Class.forName(ClassName);
          Object object1 = class1.newInstance();
          

          【讨论】:

            【解决方案8】:

            为了使用Class.forName(...) 更容易获得类的完全限定名称以创建实例,可以使用Class.getName() 方法。比如:

            class ObjectMaker {
                // Constructor, fields, initialization, etc...
                public Object makeObject(Class<?> clazz) {
                    Object o = null;
            
                    try {
                        o = Class.forName(clazz.getName()).newInstance();
                    } catch (ClassNotFoundException e) {
                        // There may be other exceptions to throw here, 
                        // but I'm writing this from memory.
                        e.printStackTrace();
                    }
            
                    return o;
                }
            }
            

            然后你可以将你得到的对象转换回你传递给makeObject(...)的任何类:

            Data d = (Data) objectMaker.makeObject(Data.class);
            

            【讨论】:

            • 你不能简单地用clazz.newInstance()代替getName然后fromName吗?
            【解决方案9】:

            从 Java 8 开始不推荐直接使用newInstance()。您需要使用Class.getDeclaredConstructor(...).newInstance(...),但有相应的例外情况。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2010-10-16
              • 1970-01-01
              相关资源
              最近更新 更多