从(超类)子类实例列表中调用静态方法

时间:2013-01-04 18:13:29

标签: java android static-methods

假设我有一个基类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子类的代码生成器模板。

但是这个(和上面的代码)看起来不是一个很好的解决方案。我理解整个应用程序设计是否有些缺陷,但即使这是您的观点,我也会感激如果这些声明增加了额外的(独立的)建设性建议。上述问题是否有更好的解决方案/习语?

1 个答案:

答案 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中。