如何创建所有子类的实例

3

我有超过250个子类需要创建实例,而我不能坐在那里并且复制粘贴250次new Class();。使用反射是否有办法来创建这些类的实例?当创建实例时不需要构造函数。 谢谢。


我们需要比这更多的信息。例如,这些实例应该在哪里创建?一些代码会很有帮助。 - Keppil
@Keppil,目前还没有实例,我需要创建它们。我需要在程序启动时创建它们。 - user1681891
我假设你知道这些类的名称,并且有一个完整的列表以及你想要创建的每个实例的数量? - Krzysztof Jabłoński
我需要这个是动态的,让一个文件扩展一个超类,并且当程序启动时,创建一个类的实例,不添加任何代码。 - user1681891
如果你有一个有包限定的类名,可以使用 Class.forName(qualifiedName).newInstance() 来获取一个实例。如果你能够解析/获得一个类名列表,那么你已经完成了大部分工作。不知道实例将如何使用,很难说。编辑:没有意识到它们都是子类。Brain的答案看起来应该可行。 - Justin
使用反射无法获取一个类或接口的所有实例。 - Steve Kuo
4个回答

3

我知道这些,但是我需要在没有类名的情况下完成所有操作。我需要循环遍历所有类,并检查其超类是否为另一个类(Class.getSuperclass()),然后实例化它。 - user1681891

2

首先,你需要获取所有的子类。那个特定的答案似乎是合法的,虽然我自己没有测试过。

然后遍历这些类并使用Class.newInstance(无参构造函数)或Class.getConstructorConstructor.newInstance(当有参数需要传递给构造函数时)来创建实例。最终的代码将如下所示:

Reflections reflections = new Reflections("my.project.prefix");
Set<Class<? extends SomeType>> subTypes = 
        reflections.getSubTypesOf(SomeType.class);
Set<SomeType> someTypes = new HashSet<SomeType>(subTypes.size());
for (Class<? extends SubType> subType : subTypes) {
    someTypes.add(subType.newInstance());
}
// Do something with someTypes here

这将获取子类,迭代它们,并创建每个子类的实例。这里有一些异常情况,我没有对其进行任何处理。您可能还需要进行一些类型转换(尽管我认为您不必这样做)。 编辑: 我上面的答案显然会导致一些虚假的类加载。请改用以下方式创建子类集:像这样直接查询存储区,避免在类加载中定义类型
Reflections reflections = new Reflections(...); //see in other use cases
Set<String> subTypeFqns = reflections.getStore().getSubTypesOf(SomeClass.class.getName());
Set<Class<?>> subTypes = new HashSet<Class<?>>();
for (String fqn : subTypeFqns) {
    subTypes.add(Class.forName(fqn));
}

那么这些行:

for (Class<? extends SubType> subType : subTypes) {
    someTypes.add(subType.newInstance());
}

成为这样:

for (Class<?> subType : subTypes) {
    someTypes.add((SomeType) subType.newInstance());
}

请注意,这将获取子子类,因此您可以通过使用“subType.getSuperclass().equals(SomeType.class)”在迭代时过滤它们,以防您不想要它们。 - Brian

0

这是一段代码,用于加载一个包中的所有类,创建它们的新实例并将它们放入哈希映射表中(我的所有类都继承自Commande):

    this.actions = new HashMap<String, Commande>();

    ServletContext sc = this.getServletContext();

    ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
    URL res = classLoader.getResource(COMMAND_DIRECTORY);
    File[] list = new File(res.getFile()).listFiles();
    String className = "";
    for (File f : list) {
        className = f.getName().replaceAll(".class$", "");
        try {
            Class<?> classe = Class.forName("org.commandes." + className);
            if (classe.getSuperclass() == Commande.class) {
                Commande c = (Commande) classe.newInstance();
                this.actions.put(c.getName(), c);
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

这里,COMMAND_DIRECTORY 对我来说是 org/commandes。

我不知道这是否是正确的方法,但这是我在 servlet 中实现命令设计模式(类似插件实现)的唯一方法。


0

您可以按照以下步骤进行:

Class instantiableClass = Class.forName("package.subpackage.ClassName");
Object instance = instantableClass.newInstance();

只有当您的类仅具有默认构造函数或公共零参数构造函数时才有效。如果需要,可以循环、泛化或复制代码。

更通用的解决方案 this 可以帮助您了解为什么不可能。您可以使用任何已知类或已知其名称的类,或者可以从任何源访问其名称,或者以任何方式提供这些最小信息。

但是,如果没有关于那些类的任何知识,几乎是不可能的。您必须寻找当前类路径中的所有类,然后检查它们的继承树以符合特定类。


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