假设我有一个基类A
(带有一个名为normalInit()
的虚方法)和300个子类:A1, A2, A3, ...
每个子类都有一个staticInit()
静态方法,加上normalInit()
覆盖。 (请不要问为什么;这是在已经给出的生产软件中,不能改变设计以便更好地重用。实际上,这些子类是由代码生成器生成的,但现在这是无关紧要的。)
根据应用程序的不同执行情况,需要初始化A1, A2, A3, ...
的(小)子集。换句话说,有些数据表明特定Ai
的所有实例通常共享或访问。显然,将这些实体定义和处理为static
成员/方法是合理的(因为它们由Ai
的所有实例共享。)
那么如何初始化该子集的静态(并调用静态方法)?
简而言之,它不是静态初始化所有 Ai
子类的解决方案,因为只需要一小部分(会浪费内存)。 Java中的static
行为显然给出了一个解决方案:在第一次访问类时初始化类的static
初始化器(我忽略了一些特殊情况,例如编译器内联的pritimive)最终的静态,就像在这种情况下,从技术上讲,没有类访问,只是在源代码级别)。
问题是,我需要 deterministic (实际上是在预定义时间)静态初始化,因为它们的static
行为也访问应用程序的当前静态(全局)状态。因此static
初始值设定项不是一个选项,我需要static
方法,以便在适当的位置明确调用它们。
在有问题的应用程序中,必须在通过迭代Ai
访问各种ArrayList<A>
类的实例时执行此操作,其中A
是超类。
for (int i = 0; i < list.size(); ++i) {
list[i].normalInit(args); // normalInit() is an instance method
}
此列表包含Ai
个实例(例如,A1
的950个实例,A2
的1750个实例等,以未分类的“随机”顺序排列。)
换句话说,我无法访问具体的类名(因此我不能只调用A4.staticInit()
),因为我不知道哪个Ai
在列表中有实例。 注意我知道静态绑定在编译时,我知道这里不可能存在多态性,所以我不会问如何从上面的循环中调用静态方法!由于动态调度,调用Class
时,具体调用的实例(以及它的normalInit()
)在运行时决定。
一个明显的解决方案是从staticInit()
覆盖中调用具体类“normalInit()
方法:
public class A2 {
@Override
public void normalInit(int[] args) {
// ...
staticInit();
}
private static void staticInit() {
if (!sStaticInitialized) {
sStaticInitialized = true;
...
}
}
}
为此,必须修改生成Ai
子类的代码生成器模板。
但是这个(和上面的代码)看起来不是一个很好的解决方案。我理解整个应用程序设计是否有些缺陷,但即使这是您的观点,我也会感激如果这些声明增加了额外的(独立的)建设性建议。上述问题是否有更好的解决方案/习语?
答案 0 :(得分:2)
好的,用反射回答:
String classPrefixName = "com.your.company.A";
for (int i = 0; i< 300; i++) {
Class<?> clazz = Class.forName(classPrefixName+i); //look for the class
Method method = clazz.getDeclaredMethod("staticInit"); //look for the method
method.invoke(null); //invoke(null), since it's a static method
}
这样您就不需要将静态方法包装在实例1中。