问题描述
假设 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} 中声称的表示}} 文件格式。
…
-
如果
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