我有一个超类,然后是几个子类,如下所示:
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>();
}
如何“神奇地”将A
的所有子类的实例添加到list
,而无需手动创建每个子类的实例并将其添加到列表中?也许使用初始化块?
修改
我在list
中访问Manager
的方式并不重要。我把它编辑为静态。
答案 0 :(得分:2)
(第二次尝试 - 我的第一次尝试是基于对该问题的误解。)
我假设您要做的是构建一个(静态)列表:
首先,实例初始化程序块不会这样做。在创建实例时运行实例初始化程序...并且必须new
类(即每个子类)才能实现此目的。
我认为唯一可行的方法是编写一些毛茸茸的反射代码:
Class.forName()
,A
的子类,这是(IMO)非常hacky !!它会很昂贵......除非你能限制需要搜索这些子类的“包空间”。
实际上,这个可能是一个使用enum
更好解决的问题...特别是如果子类没有需要的行为差异不同的方法实现。 (例如,您的getValue()
方法只能返回一个私有变量...您使用构造函数初始化。)请参阅@Paul Bellora的答案。
(阻止这种情况适用的事情是,如果需要有一些子类的多个实例。enums
无法做到这一点。)
答案 1 :(得分:1)
每个班级都代表一个命令。
根据您的问题说明,听起来A
可能是enum:
public enum A {
B(1) {
@Override
public void execute() {
//code and stuff
}
},
C(123) {
@Override
public void execute() {
//code and stuff
}
},
D(15234) {
@Override
public void execute() {
//code and stuff
}
};
private final int value;
private A(int value) {
this.value = value;
}
public int getValue() {
return value;
}
public abstract void execute();
}
现在,每个命令只有一个实例,您可以使用A.values()
轻松迭代命令。
答案 2 :(得分:0)
这有点像一种hackish方式,但如果所有子类都在一个文件夹(实际的类文件)中,你可以遍历文件夹中的文件并使用ClassLoader
。你的代码看起来像 -
for(String className : classNames){
Class clazz = classLoader.loadClass(className);
list.add(clazz.newInstance());
}
查看ClassLoader API了解更多信息。还要记住,这不是很有效,但如果你只是这样做,你应该没事。
答案 3 :(得分:0)
虽然它没有多大意义......你可以做的一种方法是,做类似Spring的组件扫描:使用像PathMatchingResourcePatternResolver
这样的东西,找出所有可能的类。迭代它们并添加到列表中,如果它是A的子类。
答案 4 :(得分:0)
可能是这样的:
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(new A());
。但我不知道这是不是你要找的......
编辑:
如何在Manager中访问列表并不重要。我把它编辑为静态。
如果你不关心使用单身,这是一个非常基本的实现:
但请阅读What is bad about singletons。
public class Manager {
private static Manager instance = null;
protected Manager() {
// Exists only to defeat instantiation.
}
public static Manager getInstance() {
if(instance == null) {
instance = new Manager();
}
return instance;
}
}
然后:
public abstract class A {
public A() {
Manager.getInstance().list.add(this);
}
public abstract int getValue();
}
public class B extends A {
}
但是,作为一种设计,这又非常令人满意......
答案 5 :(得分:0)
1)您需要找到类A的所有可用子类。为此,您需要扫描Java类路径上的所有类。为了简化操作,我们可以假设所有子类都与A.class位于同一位置。 A应该在jar或文件夹中。我们可以找到它的实际位置
URL url = A.class.getProtectionDomain().getCodeSource().getLocation();
2)让我们假设它是一个文件夹,例如file:/ D:/ workspace1 / x / target / classes /。现在我们应该遍历此文件夹和子文件夹中的所有.class文件。我们可以使用File.listFiles或Java 7 NIO2。我们有2个选项
a)加载每个类并检查其超类
Class cls = Class.forName();
if (cls.getSuperClass() == A.class) {
...
b)使用javaassist框架http://www.javassist.org或类似方法直接使用类文件
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构造函数
答案 6 :(得分:0)
如何使用类路径扫描程序自动检测目标类:
List<Class<?>> classes = CPScanner.scanClasses(new ClassFilter().packageName("com.foo.*").superClass(A.class));
由于您已获得目标类,因此可以使用newInstance方法轻松初始化它们。
顺便使用下面的maven依赖项来使用给定的代码段:
<dependency>
<groupId>net.sf.corn</groupId>
<artifactId>corn-cps</artifactId>
<version>1.1.1</version>
</dependency>
干杯。