0

I'm trying to create a subclass which auto creates itself. I defined Base which holds a list of instances. Then I defined Derived with a static member reg. reg is in place initialized by calling Base.Register(), which adds it to the instances list.

In the main() I'm printing the instances list of Base. But there is no initialization and I get an error - the instances list is null.

In a further attempt, I added a list of Booleans to Base. Whenever I register an instance, I'm changing this list. I also print this list in the program. I expected it to force the execution of the Base.register(), but to no avail.

I did find a solution that worked, but I don't appreciate - I could print the result of the Base.register() as saved in the Derived. That would force the static initialization. However, I intend to use the solution for a bunch of derived classes, and I wouldn't want to have to call each derived class directly.

Is there a way to force the static init?

I guess I could use reflections, I'm trying to avoid that at the moment.

EDIT what I am actually trying to do, is to build a set of derived classes (for unit testing). All classes derive Base. I want to avoid the need to create instances separately for each. I'm trying to get a generic solution, in each derived class code (only). Such a solution would be easy to copy & paste.

public class StaticTest {

    private static class Base{
        private static ArrayList<Base> _instances = null;
        private static ArrayList<Boolean> _regs = null;
        public static int _count = 0;
        public static void init(){
            _regs = new ArrayList<>();
            for (int i=0;i<10;i++)
                _regs.add(false);
        }
        protected static boolean register(Base b)
        {
            if (_instances == null)
                _instances = new ArrayList<>();

            _regs.set(_count++, true);

            return _instances.add(b);
        }

        public static void printAll(){
            for (Boolean b: _regs)
                System.out.printf("hello %s%n", b.toString());
            for (Base b: _instances)
                System.out.printf("hello %s%n", b.toString());
        }
    }

    private static class Derived extends Base{
        public static boolean _reg = Base.register(new Derived());
    }

    public static void main(String[] args) {
        //System.out.print(Derived._reg ? "0" : "1");
        Base.init();
        System.out.printf("Base._count = %d%n",Base._count);
        Base.printAll();
    }

}
tamir
  • 81
  • 2
  • 9
  • 1
    You can init your class in Static Initialization Block https://stackoverflow.com/questions/2420389/static-initialization-blocks – Emil Hotkowski May 27 '17 at 10:11
  • Why not have a `Base` constructor register each object, and just let derived instances be created and registered as client classes need them? – Kevin Anderson May 27 '17 at 11:35
  • After your edit, you're still asking the wrong question. This is not your problem, is the problem of the solution you're trying to apply, which is incorrect. Do you want singletons of the child classes? Why does the parent need references to singleton of the childs? It doesn't make sense, but why not save the reference of the child in the parent constructor (parent and child are the same instance)? – Sergio Otero Lopez May 27 '17 at 18:09
  • My problem is how do I create a set of instances of derived classes, without writing a long list of `new SomeDerived`. Can this be done using static initializations? Can this be done in another way? – tamir May 27 '17 at 18:13
  • You're still asking the solution of the wrong problem. You want the base class to have a list with 1 instance of each child. What for? Can you provide a real example of what you're trying to do (the test you mention and what will do base and derived)? BTW, you could only do what you say by instrospection or using a framework like Spring, but i still recommend you against this design – Sergio Otero Lopez May 27 '17 at 18:29
  • The base is the basic test, and each derived is a single test. After creating all derived tests i put them in a list, and run all tests (using the common base interface) – tamir May 27 '17 at 18:33
  • Just use JUnit. You still don't need the base class nor to register the list of instances. In case you have some common behaviour, try to use composition instead of inherintance https://github.com/junit-team/junit4/wiki/Getting-started https://courses.cs.washington.edu/courses/cse143/11wi/eclipse-tutorial/junit.shtml#creating – Sergio Otero Lopez May 27 '17 at 21:47

1 Answers1

0

Short answer is that static initialization occurs only when a class is first used. When you invoke Base.init(), Derived hasn't been yet used and so register hasn't been called.

Medium answer is that if you uncomment the line System.out, you get a NullPointerException because the static code in Derived calls to register before init initializes the Arraylist. Moving the init to the first line solves it and it works as you wanted.

Final answer, if you're trying to understand how a Java classes initializes and it's limitations, it's ok, but the mechanism you're trying to write is a very bad design. Please provide the real problem you're trying to solve and someone can point you in the right direction.