我想做这样的事情:
Listanimals = new ArrayList (); for( Class c: list_of_all_classes_available_to_my_app() ) if (c is Animal) animals.add( new c() );
所以,我想查看我的应用程序的Universe中的所有类,当我找到一个来自Animal的类时,我想创建一个该类型的新对象并将其添加到列表中.这允许我添加功能而无需更新事物列表.我可以避免以下情况:
Listanimals = new ArrayList (); animals.add( new Dog() ); animals.add( new Cat() ); animals.add( new Donkey() ); ...
通过上面的方法,我可以简单地创建一个扩展Animal的新类,它将自动被拾取.
更新:2008年10月16日上午9:00太平洋标准时间:
这个问题引起了很多很好的回应 - 谢谢.从回答和我的研究中,我发现我真正想要做的就是在Java下不可能.有一些方法,比如ddimitrov的ServiceLoader机制可以工作 - 但它们对我想要的东西非常重,我相信我只是将问题从Java代码转移到外部配置文件.
另一种表达我想要的方式:我的Animal类中的静态函数查找并实例化从Animal继承的所有类 - 无需任何进一步的配置/编码.如果我必须配置,我也可以在Animal类中实例化它们.我理解,因为Java程序只是一个松散的.class文件联合体,就像它一样.
有趣的是,在C#中,这似乎相当微不足道.
我使用org.reflections:
Reflections reflections = new Reflections("com.mycompany"); Set> classes = reflections.getSubTypesOf(MyInterface.class);
另一个例子:
public static void main(String[] args) throws IllegalAccessException, InstantiationException { Reflections reflections = new Reflections("java.util"); Set> classes = reflections.getSubTypesOf(java.util.List.class); for (Class extends List> aClass : classes) { System.out.println(aClass.getName()); if(aClass == ArrayList.class) { List list = aClass.newInstance(); list.add("test"); System.out.println(list.getClass().getName() + ": " + list.size()); } } }
Java的方法是使用ServiceLoader机制.
此外,许多人通过在一个众所周知的类路径位置(即/META-INF/services/myplugin.properties)中放置一个文件,然后使用ClassLoader.getResources()来枚举所有jar中具有此名称的所有文件.这允许每个jar导出它自己的提供者,你可以使用Class.forName()通过反射实例化它们
从面向方面的角度考虑这个问题; 你真正想知道的是,在运行时知道所有已经扩展了Animal类的类.(我认为这比你的标题更准确地描述你的问题;否则,我认为你没有运行时问题.)
所以我认为你想要的是创建一个基类(Animal)的构造函数,它添加到你的静态数组(我更喜欢ArrayLists,我自己,但更喜欢他们自己的)正在实例化的当前类的类型.
所以粗略地说;
public abstract class Animal { private static ArrayListinstantiatedDerivedTypes; public Animal() { Class derivedClass = this.getClass(); if (!instantiatedDerivedClass.contains(derivedClass)) { instantiatedDerivedClass.Add(derivedClass); } }
当然,你需要在Animal上使用一个静态构造函数来初始化instantiatedDerivedClass ...我想这会做你可能想要的.请注意,这是依赖于执行路径的; 如果您有一个源自Animal的Dog类,它永远不会被调用,那么您将不会在Animal类列表中拥有它.
不幸的是,这并不是完全可能的,因为ClassLoader不会告诉你哪些类可用.但是,你可以做到这样的事情:
for (String classpathEntry : System.getProperty("java.class.path").split(System.getProperty("path.separator"))) { if (classpathEntry.endsWith(".jar")) { File jar = new File(classpathEntry); JarInputStream is = new JarInputStream(new FileInputStream(jar)); JarEntry entry; while( (entry = is.getNextJarEntry()) != null) { if(entry.getName().endsWith(".class")) { // Class.forName(entry.getName()) and check // for implementation of the interface } } } }
编辑: johnstok是正确的(在注释中),这仅适用于独立的Java应用程序,并且不适用于应用程序服务器.