Joh*_*ada 139 java reflection inheritance
我想做这样的事情:
List<Animal> animals = new ArrayList<Animal>();
for( Class c: list_of_all_classes_available_to_my_app() )
if (c is Animal)
animals.add( new c() );
Run Code Online (Sandbox Code Playgroud)
所以,我想查看我的应用程序的Universe中的所有类,当我找到一个来自Animal的类时,我想创建一个该类型的新对象并将其添加到列表中.这允许我添加功能而无需更新事物列表.我可以避免以下情况:
List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...
Run Code Online (Sandbox Code Playgroud)
通过上面的方法,我可以简单地创建一个扩展Animal的新类,它将自动被拾取.
更新:2008年10月16日上午9:00太平洋标准时间:
这个问题引起了很多很好的回应 - 谢谢.从回答和我的研究中,我发现我真正想要做的就是在Java下不可能.有一些方法,比如ddimitrov的ServiceLoader机制可以工作 - 但它们对我想要的东西非常重,我相信我只是将问题从Java代码转移到外部配置文件.
另一种表达我想要的方式:我的Animal类中的静态函数查找并实例化从Animal继承的所有类 - 无需任何进一步的配置/编码.如果我必须配置,我也可以在Animal类中实例化它们.我理解,因为Java程序只是一个松散的.class文件联合体,就像它一样.
有趣的是,在C#中,这似乎相当微不足道.
Iva*_*Nik 149
我使用org.reflections:
Reflections reflections = new Reflections("com.mycompany");
Set<Class<? extends MyInterface>> classes = reflections.getSubTypesOf(MyInterface.class);
Run Code Online (Sandbox Code Playgroud)
另一个例子:
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Reflections reflections = new Reflections("java.util");
Set<Class<? extends List>> 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());
}
}
}
Run Code Online (Sandbox Code Playgroud)
ddi*_*rov 34
Java的方法是使用ServiceLoader机制.
此外,许多人通过在一个众所周知的类路径位置(即/META-INF/services/myplugin.properties)中放置一个文件,然后使用ClassLoader.getResources()来枚举所有jar中具有此名称的所有文件.这允许每个jar导出它自己的提供者,你可以使用Class.forName()通过反射实例化它们
从面向方面的角度考虑这个问题; 你真正想知道的是,在运行时知道所有已经扩展了Animal类的类.(我认为这比你的标题更准确地描述你的问题;否则,我认为你没有运行时问题.)
所以我认为你想要的是创建一个基类(Animal)的构造函数,它添加到你的静态数组(我更喜欢ArrayLists,我自己,但更喜欢他们自己的)正在实例化的当前类的类型.
所以粗略地说;
public abstract class Animal
{
private static ArrayList<Class> instantiatedDerivedTypes;
public Animal() {
Class derivedClass = this.getClass();
if (!instantiatedDerivedClass.contains(derivedClass)) {
instantiatedDerivedClass.Add(derivedClass);
}
}
Run Code Online (Sandbox Code Playgroud)
当然,你需要在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
}
}
}
}
Run Code Online (Sandbox Code Playgroud)
编辑: johnstok是正确的(在注释中),这仅适用于独立的Java应用程序,并且不适用于应用程序服务器.
列出给定类的所有子类的最强大的机制目前是ClassGraph,因为它处理最广泛的类路径规范机制,包括新的 JPMS 模块系统。(我是作者。)
List<Class<Animal>> animals;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("com.zoo.animals")
.enableClassInfo().scan()) {
animals = scanResult
.getSubclasses(Animal.class.getName())
.loadClasses(Animal.class);
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
135389 次 |
| 最近记录: |