【问题标题】:Calling static method from a (superclass) list of subclass instances从子类实例的(超类)列表中调用静态方法
【发布时间】:2012-12-19 05:04:14
【问题描述】:

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

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

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

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

问题是,我需要确定性(实际上是在预定义时间)静态初始化,因为它们的static 行为也访问应用程序的当前静态(全局)状态。所以static 初始化器不是一个选项,我需要static 方法,在适当的地方显式调用它们。

在有问题的应用程序中,当通过迭代 ArrayList<A> 访问各种 Ai 类的实例时必须这样做,其中 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()被调用时。

一个明显的解决方案是从 normalInit() 覆盖调用具体类的 staticInit() 方法:

public class A2 {   

    @Override
    public void normalInit(int[] args) {
        // ...       

        staticInit();
    }

    private static void staticInit() {
           if (!sStaticInitialized)  {
                sStaticInitialized = true;
                ...
           }
    }
}

为此,必须修改生成Ai 子类的代码生成器模板。

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

【问题讨论】:

  • 你试过反射吗?从由类名定义为字符串的不同类调用静态方法...
  • 这将是一个与当前解决方案类似的解决方案(只是更慢),不是吗?我仍然需要存储已经通过反射访问的 Ai 类名(以调用它们的静态方法)。
  • 使用反射可以直接访问静态方法,无需包装。缺点是在迭代之前必须将类的名称设为 String[]。
  • 回答某人的问题:超类不能调用staticInit(),因为staticInit() 是特定于A1,A2,A+的,它们每个都有不同的和自己的staticInit()。 (它不需要是私有的,但这不会改变任何东西。)
  • @ThomasCalc 反射速度较慢,但​​ 1,000 次调用不会产生显着差异(即,我们在这里说的是毫秒,如果不是微秒的话)。例如,请参阅 this post 以了解通过反射成本调用方法的成本(在您的情况下,查找方法需要更多时间)。

标签: java android static-methods


【解决方案1】:

好的,用反射来回答:

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
}

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-12-30
    • 1970-01-01
    • 2015-09-18
    • 2014-10-04
    • 2021-05-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多