在Java中实例化大量子类的最有效方法是什么



我正在处理一个项目,该项目需要使用大量扩展特定抽象类的类对象。手动实例化需要调用每个对象的单独构造函数,这开始污染我的客户端类。

这个项目的原始代码太长了,无法发布在这个网站上,所以我有一个简化的例子如下:

假设有一个抽象类叫Letter:

public abstract class Letter{
String letter;
}

以及扩展letter抽象类的26个单独的字母类:

public class A extends Letter{
this.letter = "A";
}
public class B extends Letter{
this.letter = "B";
}
... and so on

这就是我寻求帮助的地方-有一个名为Alphabet:的客户端类

public class Alphabet{
public List<Letter> getLetters(){
List<Letter> letters = new ArrayList<>();
A a = new A();
B b = new B();
C c = new C();
list.add(a);
list.add(b);
list.add(c);
...the list goes on
return letters;
}
}

正如您所看到的,手动实例化每个字母并不理想。我正在寻找一种在运行时动态创建类对象列表的方法。

也许与此类似:

public class Alphabet{
public List<Letter> getLetters(){
List<Letter> letters = getAllClassesExtending(Letter.class);
return letters;
//list would then contain A,B,C,D,E,F,G, etc.
}
}

我最终希望能够创建一个新类,并将其自动添加到客户端类中的对象列表中,而无需修改客户端类(例如,我不想显式引用客户端类中每个字母类(

这听起来像是enum的典型用例。enum的常量可以有一个带有代码的类主体,覆盖基类型的方法,甚至可以声明新字段。

获取所有子类型的实例的任务意味着一组封闭的子类型,它与enum类型的行为相匹配。

public enum Letter {
A {
@Override
public boolean isVowel() {
return true;
}
},
B, C, D,
E {
@Override
public boolean isVowel() {
return true;
}
},
F, G, H,
I {
@Override
public boolean isVowel() {
return true;
}
}, J, K, L, M, N,
O {
@Override
public boolean isVowel() {
return true;
}
}, P, Q, R, S, T,
U {
@Override
public boolean isVowel() {
return true;
}
}, V, W, X, Y, Z;
;
String letter = name();
public static List<Letter> getLetters() {
return Arrays.asList(values());
}
public boolean isVowel() {
return false;
}
}

这表明重写方法是可能的,而且获取所有实例(作为数组(的方法也是免费的。此外,这些名称是在本质上指定的,没有冗余。

如果您希望有一组开放的子类,以便在编译代码后进行潜在的扩展,那么您应该查看服务提供程序的概念和ServiceLoader类。这种机制不会自动找到子类,而只会在META-INF中的文件中或通过模块声明找到那些被声明为服务提供者的子类。另一方面,它为您提供了一个强大的、已建立的解决方案,该解决方案将由Java开发人员维护,甚至随着平台的发展而发展,比如集成到新的模块概念中。

您可以使用Reflections库在运行时查找类,例如,如果所有类都位于com.letters包下,并且有一个无参数构造函数:

public List<? extends Letter> getLetters(){
Reflections reflections = new Reflections("com.letters");
Set<Class<? extends Letter>> classes = reflections.getSubTypesOf(Letter.class);
return classes.stream()
.map(clazz -> {
try {
return clazz.newInstance();
} catch (InstantiationException | IllegalAccessException ex) {
throw new RuntimeException(ex);
}
})
.collect(Collectors.toList());
}

这不是查找类的最有效方法,如果此代码位于关键路径上,则可能需要缓存结果。

最新更新