【发布时间】:2015-02-27 20:35:58
【问题描述】:
我有一个由各种类扩展的类 X。 X 需要知道它在运行时存在的每个子类型。所以我的想法是在 X 中创建一个以 Class 作为参数的静态方法“static init()”。问题在于,在调用 init() 之前,需要通过其静态初始化块初始化 X 的子类。例如,X 可能会发现子类的一些静态字段,这些字段可能是任何声明的类型。所以以这段代码为例:
class X {
X() {
/*This would be one idea but does not work
in this concrete example.*/
init(getClass());
}
static void init(Class<? extends X> c) {
if(c.getDeclaredField("a").get(null) == null) {
throw new AssertionError();
}
}
}
class Y extends X {
static X a = new X();
static {
/*Another idea. Works totally fine but
I dont want to trust subclasses that
they do that correctly.*/
init(Y.class);
}
}
所以我正在寻找一种方法,以某种方式将我的 init() 方法称为类静态初始化的最后一步。或任何其他防止 AssertionError 发生的方法。
编辑:因为这会导致cmets中的误解,我实际上想做第二件事。我希望在子类化我的类的任何类的静态初始化中调用我的方法(直接或间接)。我不知道存在哪些子类,我对它们的结构一无所知,并且必须在运行时检查所有断言(通过反射)。我的类和子类甚至可能不会由同一台机器上的同一编译器和/或同一个人编译。
Edit2:也许我可以构建一个 ClassLoader,它是 System-ClassLoader 的简单代理,并用它替换 System-ClassLoader。如果加载的类是我的类的子类,我可以初始化它并调用我的方法。不幸的是,我(还)对 ClassLoaders 知之甚少,网上也没有太多关于这个主题的教程或帮助。那么任何有自定义类加载器经验的人都可以告诉我这是否可能吗?如果我的类路径中的某个其他库在任何时间点也安装了自定义 ClassLoader,会发生什么情况?
Edit3:我不想做的——如果有其他选择的话——是直接修改字节码。
【问题讨论】:
-
你想在这里实现什么?为什么超类应该知道它的子类?
-
第一个解决方案“init(getClass());”应该可以正常工作,如果您不在 Y 的静态初始化程序中调用 X 的构造函数(a 的类型不应该是 X 的子类型)。解决方案必须捕获“静态 X a = new X();”的情况
-
您的意图是每个子类都应该履行特定的合同,我对吗?在这种情况下,它应该包含一个不为空的字段。
-
是的,斯特凡·曼德尔,你是对的。然而,子类必须满足的规则非常复杂。它们涉及扩展类的结构、各种注释以及静态和非静态字段。是的,我专门构建了这个案例来展示一个有意义的案例,其中没有创建子类的实例。这就是为什么第一个解决方案不起作用的原因。
标签: java reflection static initialization