简体   繁体   English

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

[英]Running a Static Block Without Instantiating a Class - Java

I have several child classes extending an abstract parent class. 我有几个子类扩展了一个抽象父类。 I want the parent class to have a static ArrayList holding instances of each child. 我希望父类有一个包含每个孩子实例的静态ArrayList。 If possible, I would like to be able to add more child classes without having to change the parent class's code. 如果可能的话,我希望能够添加更多的子类而不必更改父类的代码。

One solution I came up with is to give each of the child classes a static block that will add an instance of itself to the ArrayList. 我想出的一种解决方案是为每个子类提供一个静态块,该块将自身的实例添加到ArrayList中。 The only problem with this is that I then need to make some call to each child to get it to load and run the block. 唯一的问题是,然后我需要对每个孩子进行一些调用,以使其加载并运行该块。

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());
    }    
}

Is there a way around this? 有没有解决的办法? Can I load a class without making a call to it? 我可以在不致电的情况下加载课程吗? Would there be any better ways of doing this? 会有更好的方法吗?

Edit: This is actually for a tile based game. 编辑:这实际上是针对基于图块的游戏。 I have an abstract "Tile" class and an arbitrary number of tile types extending it. 我有一个抽象的“ Tile”类和扩展它的任意数量的图块类型。 I would like to be able to easily add new tiles to the game without having to change the code all over the place. 我希望能够轻松地向游戏中添加新的图块,而不必在整个地方更改代码。 If you have a better idea for how to do this, I am open to suggestion. 如果您对如何执行此操作有更好的想法,我欢迎您提出建议。

You can do it outside the class hierarchy. 您可以在类层次结构之外进行操作。 Have a utility function that uses reflection to find all descendants of Parent and then adds them to your list. 有一个实用程序函数,该函数使用反射来查找“父级”的所有后代,然后将它们添加到列表中。

Your motivation for wanting to do this is unclear, but there are solutions that don't necessarily involve reflection. 您这样做的动机尚不清楚,但是有些解决方案不一定涉及反思。

Shift the responsibility for creating the child classes into a factory class. 将创建子类的责任转移到工厂类。 In that factory class, insert the children classes into your list as well. 在该工厂类中,还将子类插入列表中。

Here's a snippet that could do just that. 这是一个片段,可以做到这一点。 Remember: because your list is bound to Parent , you will have to cast to the correct child class type to actually use the classes later. 请记住:由于您的列表绑定到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;
    }
}

I think threre might be an easier way to do it but this class may be usefull: 我认为使用thre可能是一种更简单的方法,但是此类可能是有用的:

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, "");
    }
}

If you're working with a standard java desktop application it may work. 如果您正在使用标准的Java桌面应用程序,则可能会起作用。 This class searches for implementations of a given superclass on a your program directory tree. 此类在程序目录树中搜索给定超类的实现。 Works for jar files too. 也适用于jar文件。

You can then initialize your static field: 然后,您可以初始化您的静态字段:

abstract public class Parent {
    protected static Set<Parent> children = ClassFinder
                .<Parent> searchAllSubclasses(Parent.class, true);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM