【发布时间】: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