2

Say I have a base class A (with a virtual method called normalInit()), and 300 subclasses: A1, A2, A3, ... Each of these subclasses have a staticInit() static method, plus a normalInit() override. (Please don't ask why; this is in a production software, already given, can't change the design for better reuse. Actually, those subclasses are generated by a code generator, but this is irrelevant now.)

Depending on the different executions of the application, a (small) subset of A1, A2, A3, ... needs to be initialized. In other words, there are some data that all instances of a particular Ai share or access commonly. Obviously, it is reasonable to define and treat these entities as static members/methods (as they are shared by all instances of an Ai).

So how to initialize the statics (and call the static methods) of this subset?

To be brief, it's not a solution to static-initialize all Ai subclasses, because only a small subset will be required (would be a waste of memory). The static behavior in Java apparently gives a solution to this: the static initializers of a class are initialized when a class is accessed for the first time (I disregard some special cases here, e.g. compiler inline of pritimive final statics, as in that case, technically there is no class access, just on source code level).

The problem is, I need deterministic (actually at-predefined-time) static initialization, because their static behavior also accesses the current static (global) state of the application. So static initializers are not an option, I need static methods, to call them explicitly at the appropriate place.

In the application in question, this must be done when instances of various Ai classes are accessed via iterating through an ArrayList<A>, where A is the superclass.

for (int i = 0; i < list.size(); ++i) {
        list[i].normalInit(args); // normalInit() is an instance method
    }

This list consists of Ai instances (e.g. 950 instances of A1, 1750 instances of A2, etc., in an unsorted, "random" order).

In other words, I don't have access to concrete class names (so I can't just call A4.staticInit()), because I don't know which Ai has instances in the list. Note that I know statics are bound at compile time and I do know that polymorphism is not possible here, so I'm not asking how to call the static methods from the above loop! The concretely called instance (and thus its Class) is decided at runtime, due to dynamic dispatch, when normalInit() is called.

An apparent solution is to call the concrete class' staticInit() method from the normalInit() override:

public class A2 {   

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

        staticInit();
    }

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

For this, the code generator templates that generate the Ai subclasses must be modified.

But this (and the above code) doesn't look like a nice solution. I understand if the overall app design is somewhat flawed, but even if that's your viewpoint, I would grateful if such claims are augmented with additional (independent) constructive advice. Is there a nicer solution/idiom to the above issue?

Thomas Calc
  • 2,994
  • 3
  • 30
  • 56
  • 2
    Have you tried with reflection? Calling a static method from different classes defined by the class name as a String... – Gilberto Torrezan Jan 04 '13 at 18:20
  • That would be a similar solution (just slower) as the current one, wouldn't it? I would still need to store which Ai class names were already accessed via Reflection (to call their static methods). – Thomas Calc Jan 04 '13 at 18:22
  • Using reflection you can access the static method directly, without wrapping it. The downside is that you must have the name of the classes as String[] before iterating. – Gilberto Torrezan Jan 04 '13 at 18:28
  • Answering someone's questions: the superclass cannot call staticInit(), because staticInit() is specific to A1,A2,A+, each of them has a different and own staticInit(). (It doesn't need to be private, but this doesn't change on anything.) – Thomas Calc Jan 04 '13 at 18:28
  • @GilbertoTorrezan: ah, I see. I'll consider that approach, then. Speed-wise, though, it might be slower, if the subset is large. (Yes, I said it's small, but I think the solution should be scalable. I mean, if there are 3000 subclasses, and 500 must be initialized, Reflection might be slower in absolute time than the static boolean-based solution.) – Thomas Calc Jan 04 '13 at 18:29
  • Actually, if the list length is very large too (tens of thousands of instances), the Reflection based solution might be able to cope with it, but I guess that the static boolean checking would still win. But I'm aware this is a perf question and doesn't have to do with my original question. – Thomas Calc Jan 04 '13 at 18:32
  • 1
    @ThomasCalc Reflection is slower but 1,000 calls won't make a noticeable difference (i.e. we are talking milli if not microseconds here). See for example [this post](http://stackoverflow.com/questions/14146570/calling-a-getter-in-java-though-reflection-whats-the-fastest-way-to-repeatedly/14146641#14146641) to get an idea of how much calling a method via reflection costs (in your case, looking up the method is what will take more time). – assylias Jan 04 '13 at 18:42

1 Answers1

2

Ok, answering it using reflection:

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
}

That way you don't need to wrap the static method inside an instance one.

Gilberto Torrezan
  • 5,113
  • 4
  • 31
  • 50