Constructor in a class of static methods

3.3k views Asked by At

I've got a class of static methods that can be performed on a map held within the class, and I want the map to be set up when the class is called. I've tried using a private contructor, but it isn't being called. The relevant parts of my code are:

public class MyClass
{
    private static final String KEYS = "ABC";
    private static final String[] DATA = {"AAA", "BBB", "CCC"};
    private static HashMap<Character, String> myMap;

    private MyClass() {
        System.out.println("Running constructor");
        populateMyMap();
    }

    private static void populateMyMap() {
        myMap = new HashMap<Character, String>();
        for (int i=0; i < KEYS.length; i++) {
            myMap.put(KEYS.charAt(i), DATA[i]);
        }
    }

    //various static methods
}

Is a private constructor the right thing to be using here, and if so what am I doing wrong?

Sorry if this is a duplicate; I've tried searching for answers, but I'm not sure what to search for!

4

There are 4 answers

1
A.H. On BEST ANSWER

The static initializer block has been mentioned in several other answers. But practically I find the following idiom more frequently in the wild:

public class MyClass
{
    private static HashMap<Character, String> myMap = createMyMap();

    private static HashMap<Character, String> createMyMap() {
        HashMap<Character, String> myTmpMap = new HashMap<Character, String>();
        for (int i=0; i < KEYS.length; i++) {
            myTmpMap.put(KEYS.charAt(i), DATA[i]);
        }
        return myTmpMap;
    }
}
0
DJClayworth On

There are two ways of achieving this. One is to make the "populateMyMap" method a static initializer (or the approach suggested by A.H.). Then it is guaranteed to be executed before the first static call. This is usually the best way, assuming that either the cost of running populateMyMap is small enough not to be noticed, or if you are going to use the functionality of the class nearly every time the application is run.

The alternative approach is what you would use if running "populateMyMap" is something that takes a significant amount of time AND either you either might not use the functionality for some executions of the app, or you want to defer the execution of populateMyMap until the data is needed, so as not to unnecessarily increase startup time.

If the second approach is what you want then you should switch structures and use a Singleton rather than static methods. Make the methods (and data) non-static and have each user of them get the Singleton instance before calling the method on it. Have "populateMyMap" called in the (private) constructor. Yes I know, Singletons have a bad reputation and people always say "avoid them because they are just global methods in disguise", but static methods are also just global methods. You're losing nothing. And this way you don't pay the cost of executing populateMyMap until (or unless) you need to.

WARNING: If your data structures are not immutable, i.e they can be changed after they are initialized, then you probably shouldn't be using any of these structures.

0
Christian Kuetbach On

Use the static initializer:

public class MyClass
{
    static {
    //init
    }
}
1
Mark Peters On

No, a private constructor is not what you want. A constructor initializes an instance of your class (when you call new MyClass()) , but static state does not belong to an instance and so shouldn't be initialized from the constructor. Initialization that you want to happen when the class is first loaded should be in a static block placed at the class level.

static {
   populateMyMap();
}

But you should never be using static (global) state. Static state makes your system prohibitively difficult to test, it is more nuanced than instance state (for example, you have one copy per load of the class) and it is typically harder to make thread safe.

Consider making your map an instance member of your class instead.