我有几个扩展抽象父类的子类。我希望父类有一个静态ArrayList来保存每个子节点的实例。如果可能的话,我希望能够添加更多子类而无需更改父类的代码。
我提出的一个解决方案是为每个子类提供一个静态块,它将自己的实例添加到ArrayList。唯一的问题是我需要调用每个子进程来加载并运行块。
abstract public class Parent {
protected static ArrayList<Parent> children = new ArrayList<Parent>();
}
public class ChildA extends Parent {
static {
children.add(new ChildA());
}
}
public class ChildB extends Parent {
static {
children.add(new ChildB());
}
}
有解决方法吗?我可以在不打电话的情况下加载课程吗?会有更好的方法吗?
编辑: 这实际上是基于磁贴的游戏。我有一个抽象的“Tile”类和任意数量的tile类型来扩展它。我希望能够轻松地为游戏添加新的磁贴,而无需在整个地方更改代码。如果您对如何做到这一点有更好的了解,我愿意接受建议。
答案 0 :(得分:0)
您可以在类层次结构之外执行此操作。有一个实用程序函数,它使用反射来查找Parent的所有后代,然后将它们添加到列表中。
答案 1 :(得分:0)
你想要做到这一点的动机尚不清楚,但有些解决方案并不一定涉及反思。
将创建子类的职责转移到工厂类中。在该工厂类中,也将子类插入到列表中。
这是一个可以做到这一点的片段。请记住:因为您的列表绑定到Parent
,您必须转换为正确的子类类型,以便以后使用类。
public final class ChildFactory {
private static ChildFactory instance = new ChildFactory();
private ChildFactory() {
}
public <C extends Parent> C generateChild(Class<C> childClass) {
try {
final C child = childClass.newInstance();
Parent.children.add(child);
return child;
} catch(InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
public static ChildFactory getInstance() {
return instance;
}
}
答案 2 :(得分:0)
我认为这可能是一种更简单的方法,但这个类可能很有用:
package classFinder;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Modifier;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
public class ClassFinder {
protected static Class<?> getClass(String prefix, String classPath)
throws ClassNotFoundException {
if (!classPath.endsWith(".class") || !classPath.startsWith(prefix)) {
return null;
}
return Class.forName(classPath.substring(prefix.length(),
classPath.length() - ".class".length()).replace('/', '.'));
}
protected static Class<?> getClass(File rootFile, File classFile)
throws ClassNotFoundException {
return getClass(rootFile.getPath() + '/', classFile.getPath());
}
@SuppressWarnings("unchecked")
protected static <T> Set<Class<T>> searchAllSubclassesInDirectory(
File rootFile, File searchFile, Class<?> cls,
boolean abstractClasses) throws ClassFinderException {
Set<Class<T>> result = new HashSet<Class<T>>();
if (searchFile.isDirectory()) {
for (File file : searchFile.listFiles()) {
result.addAll(ClassFinder.<T> searchAllSubclasses(
rootFile.getPath(), file.getPath(), cls,
abstractClasses));
}
return result;
}
String fileName = searchFile.getName();
if (!fileName.endsWith(".class")) {
return result;
}
try {
Class<?> entry = getClass(rootFile, searchFile);
if (entry != null
&& (abstractClasses || !Modifier.isAbstract(entry
.getModifiers()))) {
Class<?> superClass = entry;
while (!((superClass = superClass.getSuperclass()) == null)) {
if (superClass.equals(cls)) {
result.add((Class<T>) entry);
return result;
}
}
}
return result;
} catch (ClassNotFoundException e) {
// e.printStackTrace(); //DEBUG only
return result;
}
}
@SuppressWarnings("unchecked")
protected static <T> Set<Class<T>> searchAllSubclassesInJar(File jar,
Class<?> cls, boolean abstractClasses) {
Set<Class<T>> result = new HashSet<Class<T>>();
try {
JarFile jarFile = new JarFile(jar);
Enumeration<JarEntry> entries = jarFile.entries();
while (entries.hasMoreElements()) {
JarEntry file = entries.nextElement();
if (file.isDirectory()) {
continue;
}
Class<?> entry = getClass("", file.getName());
if (entry != null
&& (abstractClasses || !Modifier.isAbstract(entry
.getModifiers()))) {
Class<?> superClass = entry;
while (!((superClass = superClass.getSuperclass()) == null)) {
if (superClass.equals(cls)) {
result.add((Class<T>) entry);
}
}
}
}
jarFile.close();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return result;
}
protected static <T> Set<Class<T>> searchAllSubclasses(String rootPath,
String searchPath, Class<?> cls, boolean abstractClasses)
throws ClassFinderException {
if (searchPath.endsWith(".jar")) {
return searchAllSubclassesInJar(new File(searchPath), cls,
abstractClasses);
// return new HashSet<Class<T>>();
} else {
return searchAllSubclassesInDirectory(new File(rootPath), new File(
searchPath), cls, abstractClasses);
}
}
// TODO create public method to search inside a not root directory/package
public static <T> Set<Class<T>> searchAllSubclasses(Class<?> cls,
boolean abstractClasses) throws ClassFinderException {
Set<Class<T>> result = new HashSet<Class<T>>();
String classpath = System.getProperty("java.class.path");
for (String path : classpath
.split(System.getProperty("path.separator"))) {
result.addAll(ClassFinder.<T> searchAllSubclasses(path, path, cls,
abstractClasses));
}
return result;
// return ClassFinder.<T> searchAllSubclasses(ROOT_URL, cls,
// abstractClasses, "");
}
}
如果您正在使用标准的Java桌面应用程序,它可能会起作用。 此类在程序目录树中搜索给定超类的实现。也适用于jar文件。
然后,您可以初始化静态字段:
abstract public class Parent {
protected static Set<Parent> children = ClassFinder
.<Parent> searchAllSubclasses(Parent.class, true);
}