获取超类的类名? 5.3.5. Deriving a Class from a class File Representation

问题描述

我正在编写一些代码来检查其他人代码的结构。

假设 ClassB 扩展了 ClassA

我知道我能做到

Class clazz = Class.forName("classB");
clazz.getSuperclass();
clazz.getName(); //ClassA

但我不想这样做,因为它要求我的 jvm 返回 ClassA 的实际类(不在类路径中)

目前我正在使用

Class clazz = Class.forName("classB",false,classLoader);

不初始化类,这样我就不必将这么多不相关的 jar 放入我的类路径中。

有没有一种方法可以从 ClassB 中获取 Super 的类名,而无需我在类路径中包含 ClassA 的 jar?

解决方法

里面有一个根本的误解

目前我正在使用

Class clazz = Class.forName("classB",false,classLoader);

不初始化类,这样我就不必将这么多不相关的 jar 放入我的类路径中。

initialize 参数指定是否应该运行静态初始值设定项,即 static {} 块和 static 字段的非常量初始值设定项表达式。它不会阻止超类的加载。这根本不可能。

认为超类或其包含的 jar 文件“无关紧要”也很奇怪。超类是类的关键方面。

JVM 规范说:

5.3.5. Deriving a Class from a class File Representation

以下步骤用于为 Class 表示的非数组类或接口 C 派生 N 对象,使用加载程序 L 从 {{1} 中声称的表示}} 文件格式。

  1. 如果 class 有一个直接超类,从 C 到它的直接超类的符号引用使用 §5.4.3.1 的算法解析。请注意,如果 C 是一个接口,它必须将 C 作为其直接超类,该超类必须已经加载。只有 Object 没有直接超类。

    由于类或接口解析而可能引发的任何异常都可以作为此加载阶段的结果而引发。另外,这个加载阶段必须检测以下错误:

    • 如果 Object 的任何超类是 C 本身,加载会抛出一个 C

    • 否则,如果命名为 ClassCircularityError 的直接超类的类或接口实际上是接口或 C 类,则加载会抛出 final

    • 否则,如果 IncompatibleClassChangeError 是一个类并且在 C 中声明的某些实例方法可以覆盖 (§5.4.5) 在超类中声明的 C 实例方法final,加载会抛出一个 C

不加载超类就不可能执行这些强制性检查。

原则上,通过读取和解析类文件,可以在不加载类本身的情况下读取类的超类声明,这也防止了各种链接问题。只需稍加改动,this answer 的代码就可以读取超类名称而不是类名称。

仍然不能改变没有超类就不能使用类的事实,所以它的用处是有限的。

IncompatibleClassChangeError

另见§4. The class File Format