Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/ssh/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何自动将子类放入ArrayList?_Java - Fatal编程技术网

Java 如何自动将子类放入ArrayList?

Java 如何自动将子类放入ArrayList?,java,Java,我有一个超类,还有几个子类,如下所示: public abstract class A { public abstract int getValue(); } public class B extends A { public int getValue() { return 1; } } public class C extends A { public int getValue() { return 123; } }

我有一个超类,还有几个子类,如下所示:

public abstract class A {
    public abstract int getValue();
}

public class B extends A {
    public int getValue() {
        return 1;
    }
}

public class C extends A {
    public int getValue() {
        return 123;
    }
}

public class D extends A {
    public int getValue() {
        return 15234;
    }
}
大约有100个子类。我还有一位经理:

public class Manager {
    public static ArrayList<A> list = new ArrayList<A>();
}
公共类管理器{
public static ArrayList list=new ArrayList();
}
如何“神奇地”将
A
的所有子类的实例添加到
list
中,而不手动创建每个子类的实例并将其添加到列表中?也许使用初始化块

编辑


如何访问
管理器中的
列表
,并不重要。我将其编辑为静态。

这是一种有点粗俗的方式,但是如果所有子类都在一个文件夹中(实际的类文件),您可以迭代文件夹中的文件并使用
类加载器
。你的代码看起来像是这样的-

for(String className : classNames){
    Class clazz = classLoader.loadClass(className);
    list.add(clazz.newInstance());
}

有关更多信息,请参阅。还请记住,这不是很有效,但如果你只是这样做一次,你应该很好

虽然没有什么意义。。。一种方法是,执行类似于Spring组件扫描的操作:使用类似于
PathMatchingResourcePatternResolver
的方法,找出所有可能的类。如果这是a.的子类,则遍历它们并添加到列表中。

(第二次尝试-我的第一次尝试是基于对问题的误解。)

我假设您要做的是构建一个(静态)列表:

  • 仅包含每个子类的一个实例
  • 提前创建和填充,以及
  • 不涉及在每个子类中创建/添加自身实例到列表的代码
首先,实例初始值设定项块不会这样做。创建实例时会运行实例初始值设定项。。。必须
new
类(即每个子类)才能发生这种情况

我认为唯一可行的方法是编写一些毛茸茸的反射代码:

  • 迭代类路径上的所有类
  • 使用
    Class.forName()
    加载每个
  • 反射性地测试类是否是
    a
    的子类
  • 如果是,则反射地调用classes no args构造函数,并将结果实例添加到“列表”中
这(依我看)相当骇客!!而且会很贵。。。除非您可以限制需要搜索这些子类的“包空间”


实际上,使用
enum
可以更好地解决这个问题。。。特别是如果子类没有需要不同方法实现的行为差异。(例如,您的
getValue()
方法可以只返回一个私有变量……您可以使用构造函数初始化它。)请参阅@Paul Bellora的答案

(如果需要某些子类的多个实例,则会阻止此操作的应用。
枚举不可能做到这一点)

可能是这样的:

public abstract class A {
    public A(Manager m) {
        m.list.add(this);
    }
    public abstract int getValue();
}

public class B extends A {
    public B(Manager m) {
        super(m);
    }
}
这样你就不再需要处理
m.list.add(newa())子类化时。但我不知道这是否是你想要的


编辑:

如何在Manager中访问列表并不重要。我把它编辑成静态的

如果您不关心使用单例,下面是一个非常基本的实现:

但是请阅读

然后:

但是,作为一种设计,这也是非常不令人满意的…


每个类将表示一个命令

根据对问题的描述,听起来
A
可能是:

现在,每个命令只有一个实例,您可以使用
A.values()

1)轻松地迭代命令。您需要找到类A的所有可用子类。为此,您需要扫描Java类路径上的所有类。为了使事情更简单,我们可以假设所有子类都与.class位于同一位置。A应该放在罐子或文件夹中。我们可以找到它的实际位置

URL url = A.class.getProtectionDomain().getCodeSource().getLocation();
2) 假设它是一个文件夹,例如文件:/D:/workspace1/x/target/classes/。现在我们应该遍历此文件夹和子文件夹中的所有.class文件。我们可以使用File.listFiles或Java7NIO2来实现这一点。我们有两个选择

a) 加载每个类并检查其超类

   Class cls = Class.forName();
   if (cls.getSuperClass() == A.class) {
     ...
b) 使用javaassist框架或类似工具直接处理类文件

DataInputStream ds = new DataInputStream(new BufferedInputStream(path));
ClassFile cf =  new ClassFile(ds);
String superClass = cf.getSuperClass();
if (superClass.equals("A")) {
    Class cls = Class.forName(cf.getName());
...
选项b只加载您实际需要的类,选项a更简单,但它加载文件夹中的所有类

在这两种情况下,都将实例的

A a = (A) cls.newInstance();

假设所有子类都没有arg构造函数

如何使用类路径扫描程序自动检测目标类:

   List<Class<?>> classes = CPScanner.scanClasses(new ClassFilter().packageName("com.foo.*").superClass(A.class));

list这听起来是一件不同寻常的事情。你到底想达到什么目的?你能解释一下你要解决的问题吗?第一个问题当然是:为什么?你在做什么需要你这么做。第二个问题是:为什么?列表管理器只关心A,并将从中提取的任何项转换为类型A。每个类都有一个实现。。。让我来解释一下,每个类将代表一个命令。将有一个获取命令名的方法,一个在执行命令时调用的方法,以及其他一些东西。我不想做
list.add(newd())@兰瑟姆斯,请解释清楚一点。我希望被子类化,因为每个命令都可以在类型转换到超类时执行。如果我有办法得到一个类名列表,这就行了。由于某种原因,如果不手动初始化,我无法获取类的名称。@blake305就像我之前说过的,如果你知道所有实际的类文件在哪里,你可以创建一个文件对象来读取
DataInputStream ds = new DataInputStream(new BufferedInputStream(path));
ClassFile cf =  new ClassFile(ds);
String superClass = cf.getSuperClass();
if (superClass.equals("A")) {
    Class cls = Class.forName(cf.getName());
...
A a = (A) cls.newInstance();
   List<Class<?>> classes = CPScanner.scanClasses(new ClassFilter().packageName("com.foo.*").superClass(A.class));
<dependency>
    <groupId>net.sf.corn</groupId>
    <artifactId>corn-cps</artifactId>
    <version>1.1.1</version>
</dependency>