在运行时,查找Java应用程序中扩展基类的所有类
我想这样做:在运行时,查找Java应用程序中扩展基类的所有类,java,reflection,inheritance,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() ); for (String classpathEntry : System.getProperty("java.class.path").split(
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() );
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
}
}
}
}
列表看起来不错。同样来自于@Luke Hutchison的作品看起来很有趣。答案中还有更多的可能性
另一种说明我想要什么的方法是:我的Animal类中的静态函数查找并实例化从Animal继承的所有类,而无需任何进一步的配置/编码。如果我必须进行配置,我也可以在Animal类中实例化它们。我理解这一点,因为Java程序只是.class文件的松散联合体,这就是它的方式
有趣的是,这似乎是在C#中。Java动态加载类,因此您的类范围将仅是那些已经加载(但尚未卸载)的类。也许您可以使用自定义类装入器来检查每个装入类的超类型。我认为没有API来查询加载的类集。不幸的是,这不完全可能,因为类加载器不会告诉您哪些类可用。但是,您可以非常接近地执行以下操作:
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() );
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应用程序,在应用程序服务器下不起作用。这是一个棘手的问题,您需要使用静态分析来找出这些信息,在运行时不容易获得。
基本上,获取应用程序的类路径,扫描可用的类,并读取它从哪个类继承的类的字节码信息。请注意,类别狗可能不会直接从动物继承,但可能会从宠物继承,而宠物又反过来从动物继承,因此您需要跟踪该层次结构。感谢所有回答此问题的人
看来这确实是个难题。我最终放弃了,在我的基类中创建了一个静态数组和getter
public abstract class Animal{
private static Animal[] animals= null;
public static Animal[] getAnimals(){
if (animals==null){
animals = new Animal[]{
new Dog(),
new Cat(),
new Lion()
};
}
return animals;
}
}
Java似乎不像C#那样为自我发现性而设置。我认为问题在于,因为Java应用程序只是某个目录/jar文件中的.class文件的集合,所以运行时在引用类之前不知道该类。在那个时候,加载程序加载它——我试图做的是在引用它之前发现它,这是不可能的,如果不到文件系统并查看它的话
我总是喜欢能够发现自己的代码,而不是我必须告诉它自己,但唉,这也行得通
再次感谢 一种方法是让类使用静态初始值设定项。。。我不认为这些是遗传的(如果它们是遗传的,则不会起作用):
它要求您将此代码添加到所有涉及的类中。但它避免了在某个地方出现一个丑陋的大循环,测试每个班级寻找动物的孩子。从面向方面的角度思考这个问题;实际上,您要做的是在运行时了解扩展了Animal类的所有类。(我认为这比你的标题更准确地描述了你的问题;否则,我认为你没有运行时问题。)
因此,我认为您需要创建基类(Animal)的构造函数,它将当前实例化的类的类型添加到静态数组中(我更喜欢ArrayList,但每个都是自己的)
所以大致上,
public abstract class Animal
{
private static ArrayList<Class> instantiatedDerivedTypes;
public Animal() {
Class derivedClass = this.getClass();
if (!instantiatedDerivedClass.contains(derivedClass)) {
instantiatedDerivedClass.Add(derivedClass);
}
}
公共抽象类动物
{
私有静态ArrayList实例化的DelivedTypes;
公共动物(){
Class-derivedClass=this.getClass();
如果(!实例化的derivedClass.contains(derivedClass)){
实例化derivedClass.Add(derivedClass);
}
}
当然,在Animal上需要一个静态构造函数来初始化实例化的DerivedClass…我认为这可能会满足您的需要。请注意,这取决于执行路径;如果您有一个从Animal派生而来的Dog类从未被调用,那么您的Animal类列表中就不会有它。实现您所需的Java方法是使用该机制
此外,许多人通过在一个众所周知的类路径位置(即/META-INF/services/myplugin.properties)中拥有一个文件,然后使用枚举所有jar中具有此名称的所有文件来实现自己的滚动。这允许每个jar导出自己的提供者,并且您可以使用Class.forName()通过反射来实例化它们我使用包级注释非常优雅地解决了这个问题,然后使该注释具有一个类列表作为参数
实现只需创建一个package-info.java,并将magic注释与它们想要支持的类列表放在一起。我使用:
Reflections=newreflections(“com.mycompany”);
设置您可以从
如果您需要一些简单而快速的东西,而无需重构任何现有代码
下面是一个未加载任何类的简单示例:
package test;
import java.util.Set;
import net.sourceforge.stripes.util.ResolverUtil;
public class BaseClassTest {
public static void main(String[] args) throws Exception {
ResolverUtil<Animal> resolver = new ResolverUtil<Animal>();
resolver.findImplementations(Animal.class, "test");
Set<Class<? extends Animal>> classes = resolver.getClasses();
for (Class<? extends Animal> clazz : classes) {
System.out.println(clazz);
}
}
}
class Animal {}
class Dog extends Animal {}
class Cat extends Animal {}
class Donkey extends Animal {}
封装测试;
导入java.util.Set;
导入net.sourceforge.stripes.util.ResolverUtil;
公共类基类测试{
公共静态void main(字符串[]args)引发异常{
ResolverUtil resolver=新ResolverUtil();
分解器。FindImplements(动物级,“测试”);
使用设置,您可以执行以下操作:
List<Animal> animals = new ArrayList<Animal>();
animals.add( new Dog() );
animals.add( new Cat() );
animals.add( new Donkey() );
...
String package = "com.mycompany";
List<Animal> animals = new ArrayList<Animal>();
for(PojoClass pojoClass : PojoClassFactory.enumerateClassesByExtendingType(package, Animal.class, null) {
animals.add((Animal) InstanceFactory.getInstance(pojoClass));
}
String package=“com.mycompany”;
列出动物=新建ArrayList();
for(PojoClass PojoClass:PojoClassFactory.enumerateClassesByExtendingType)(包,Animal.class,null){
add((Animal)InstanceFactory.getInstance(pojoClass));
}
使用此
public static Set<Class> getExtendedClasses(Class superClass)
{
try
{
ResolverUtil resolver = new ResolverUtil();
resolver.findImplementations(superClass, superClass.getPackage().getName());
return resolver.getClasses();
}
catch(Exception e)
{Log.d("Log:", " Err: getExtendedClasses() ");}
return null;
}
getExtendedClasses(Animals.class);
公共静态集getExtendedClasses(类超类)
{
尝试
{
ResolverUtil resolver=新ResolverUtil();
解析程序.findImplements(超类,超类.getPackage().getName());
返回resolver.getClasses();
}
捕获(例外e)
{Log.d(“Log:,“Err:getExtendedClasses()”);}
返回null;
}
getExtendedClasses(一个
public static Set<Class> getExtendedClasses(Class superClass)
{
try
{
ResolverUtil resolver = new ResolverUtil();
resolver.findImplementations(superClass, superClass.getPackage().getName());
return resolver.getClasses();
}
catch(Exception e)
{Log.d("Log:", " Err: getExtendedClasses() ");}
return null;
}
getExtendedClasses(Animals.class);
List<Class<Animal>> animals;
try (ScanResult scanResult = new ClassGraph().whitelistPackages("com.zoo.animals")
.enableClassInfo().scan()) {
animals = scanResult
.getSubclasses(Animal.class.getName())
.loadClasses(Animal.class);
}