2

假设我有一个基类A(带有一个名为 的虚拟方法normalInit())和 300 个子类:A1, A2, A3, ...每个子类都有一个staticInit()静态方法,外加一个normalInit()覆盖。(请不要问为什么;这是在生产软件中,已经给出,无法更改设计以更好地重用。实际上,这些子类是由代码生成器生成的,但现在这无关紧要。)

根据应用程序的不同执行,A1, A2, A3, ...需要初始化一个(小)子集。换句话说,有一些数据是特定的所有实例Ai共同共享或访问的。显然,将这​​些实体定义和处理为static成员/方法是合理的(因为它们由 a 的所有实例共享Ai)。

那么如何初始化这个子集的静态(并调用静态方法)呢?

简而言之,它不是静态初始化所有 Ai子类的解决方案,因为只需要一个小子集(会浪费内存)。staticJava 中的行为显然提供了一个解决方案:static当第一次访问一个类时,一个类的初始化器被初始化(我在这里忽略了一些特殊情况,例如编译器内联原始最终静态,就像在那种情况下,技术上存在没有类访问权限,仅在源代码级别上)。

问题是,我需要确定性(实际上是在预定义时间)静态初始化,因为它们的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实例组成(例如 950 个实例A1、1750 个 实例A2等,按未排序的“随机”顺序)。

换句话说,我无权访问具体的类名(所以我不能只调用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必须修改生成子类的代码生成器模板。

但是这个(和上面的代码)看起来不是一个好的解决方案。我了解整体应用程序设计是否存在一些缺陷,但即使这是您的观点,如果此类声明能够通过额外的(独立的)建设性建议来增强,我将不胜感激。上述问题是否有更好的解决方案/习语?

4

1 回答 1

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
}

这样您就不需要将静态方法包装在实例中。

于 2013-01-04T18:34:32.490 回答