有没有办法通过使用类加载器信息来查找扩展特定类的所有类名?
更详细的说明
我有一个 jar 文件,其中包含 3 个类 X
(extends A
)、Y
(extends A
)和 Z
(扩展 B
)。我已将此 jar 文件放入类路径中并启动 JVM(调用某个类的 main 方法)。现在从这个 main 方法有什么方法可以找到 A
的子类吗?即类X
和Y
,因为它们扩展了类A
。
最佳答案
不幸的是,没有简单的方法可以做到这一点。在类加载器加载特定类之前,JVM 没有有关该类的信息。但要让类加载器实际加载类,您必须知道类的名称。先有鸡还是先有蛋的问题。
但是,还有其他一些但更复杂的方法。
- 要确定运行应用程序时类路径上有哪些
.jar
文件,您可以调用System.getProperty("java.class.path")
然后拆分沿File.separatorChar
字符的类路径条目。类路径条目可能很多,请考虑以某种方式过滤它们(仅限制到特定目录,忽略诸如rt.jar
等标准条目) - 如果您知道哪个
.jar
文件包含您感兴趣的类,则可以使用类JarFile
的实例打开它。然后,您可以迭代所有条目(例如.class
文件),并从 JAR 文件中的内部路径构建它们的完全限定类名。 - 有了类名,你就可以调用
Class.forName()
来加载类,然后你可以使用反射来获取每个类的父类(super class),以判断它是否扩展了你的类。是否属于特定类别。
请注意,此方法非常消耗资源,您使 JVM 实际上从一个 .jar
文件(或多个 .jar
文件)加载所有类,甚至如果您以后不再使用它们。这浪费了相当多的 af 内存(PermGen 空间)。
有一些操作 Java 字节码和类文件的低级库(请参阅 BCEL 或 ASM )。使用它们,您将能够确定类的父类(super class),而无需实际(类)加载它,因此这种方式更快并且使用更少的内存。
您的问题类似于部署 Web 应用程序时 JavaEE 应用程序服务器的工作方式。为了找出要加载和初始化哪些类(例如 HTTP servlet),他们必须检查 Web 存档中的所有类,以查找特定的 Java 注释或父类(super class)。不过,他们至少知道要扫描哪个 .war
文件。例如,Apache Tomcat 使用 BCEL 而不是 Java 类加载机制。
如果您正在为应用程序设计某种动态类加载机制,请考虑其他设计选项来缩小加载程序必须扫描的类的数量,以找到要加载的正确类:告诉 的确切名称>.jar
文件而不是将其放在类路径上,而是使用 JAR 中的一些元信息(您可以使用前面提到的 JarFile
来读取 META-INF/manifest 中的条目.mf
文件)来指定要查找的类等。
关于java - 在 JVM 运行时查找类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9124740/