在不实例化类的情况下运行静态块 - Java

时间:2014-11-21 23:13:38

标签: java classloader static-block

我有几个扩展抽象父类的子类。我希望父类有一个静态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类型来扩展它。我希望能够轻松地为游戏添加新的磁贴,而无需在整个地方更改代码。如果您对如何做到这一点有更好的了解,我愿意接受建议。

3 个答案:

答案 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);
}