有没有办法在Java中通过名称实例化类?


102

我一直在寻找一个问题:从其字符串名称实例化一个类,该字符串名称描述了如何在拥有名称时实例化一个类。有没有办法用Java做到这一点?我将拥有包名称和类名称,并且我需要能够创建具有该特定名称的对象。


我们实例化一个,结果是一个对象(或:instance)。
Andreas Dolk 2012年

1
答案是肯定的,但是我认为您应该问一下它是否是一个好主意。强大的力量(反思)带来巨大的责任,只有在了解并考虑了后果之后,才应使用它。
c1moore

Answers:


238

两种方式:

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

如果您的类具有无参数构造函数,则可以Class使用Class.forName()并使用该newInstance()方法创建一个实例(尽管请注意,此方法通常被认为是有害的,因为它可以击败Java的已检查异常),因此可以使用该对象。

例如:

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

方法2

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

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

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

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

嗨,一旦我们从创建了对象newInstance(),是否可以将其投射回我们自己的对象?
GMsoF 2014年

@Simon您能详细说明/提供有关安全管理器的指针吗?
拉姆

我不明白 我想访问其他目录中未知文件中的类,我只将路径/文件的名称作为字符串。字符串“ dir / unkonwn.java”。调用Class.forName(“ dir / unknown”)给我错误。
约翰·克特吉克

我们怎样才能投instancecom.foo.MyClass?鉴于com.foo.MyClass只是一个字符串
Sanket9394 '19

14
MyClass myInstance = (MyClass) Class.forName("MyClass").newInstance();

15
值得一提的是,如果类没有无参数构造函数(并且具有其他构造函数),或者无参数构造函数不可访问,则此方法将无效。
达伍德·伊本·卡里姆


3

为了更轻松地获取类的完全限定名称,以便使用创建实例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);

1
您能不能简单地clazz.newInstance()代替getName然后fromName呢?
user276648 '16

1

使用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);
         }
      }
   }

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




0

这样的事情应该工作...

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

0

使用newInstance()直接被弃用的Java 8中,您需要使用Class.getDeclaredConstructor(...).newInstance(...)具有相应例外。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.