Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to force instantiation of static fields

Tags:

java

static

I was quite surprised of the output of the following code:

Country class

public class Country {

    private static Map<String, Country> countries = new HashMap<String, Country>();

    private final String name;

    @SuppressWarnings("LeakingThisInConstructor")
    protected Country(String name) {
        this.name = name;
        register(this);
    }

    /** Get country by name */
    public static Country getCountry(String name) {
        return countries.get(name);
    }

    /** Register country into map */
    public static void register(Country country) {
        countries.put(country.name, country);
    }

    @Override
    public String toString() {
        return name;
    }

    /** Countries in Europe */
    public static class EuropeCountry extends Country {

        public static final EuropeCountry SPAIN = new EuropeCountry("Spain");
        public static final EuropeCountry FRANCE = new EuropeCountry("France");

        protected EuropeCountry(String name) {
            super(name);
        }
    }

}

Main method

System.out.println(Country.getCountry("Spain"));

Output

null

Is there any clean way of forcing the class that extend Country to be loaded so the countries map contains all the Country instances?

like image 380
eliocs Avatar asked May 11 '11 11:05

eliocs


People also ask

How do you initialize a static field?

The only way to initialize static final variables other than the declaration statement is Static block. A static block is a block of code with a static keyword. In general, these are used to initialize the static members. JVM executes static blocks before the main method at the time of class loading.

Can static variables be instantiated?

Static variables are initialized only once , at the start of the execution. These variables will be initialized first, before the initialization of any instance variables. A single copy to be shared by all instances of the class. A static variable can be accessed directly by the class name and doesn't need any object.

Can static variables be initialized in constructor?

If you declare a static variable in a class, if you haven't initialized it, just like with instance variables compiler initializes these with default values in the default constructor. Yes, you can also initialize these values using the constructor.


2 Answers

Yes, use static initializer block:

public class Country {

    private static Map<String, Country> countries = new HashMap<String, Country>();

    static {
        countries.put("Spain", new EuroCountry("Spain"));

    }

...
like image 175
Peter Knego Avatar answered Oct 06 '22 06:10

Peter Knego


Your class EuropeCountry was not loaded at the time you called Country.getCountry("Spain"). The correct solution would be

private static Map<String, Country> countries = new HashMap<String, Country>();

static {
    // Do something to load the subclass
    try {
        Class.forName(EuropeCountry.class.getName());
    } catch (Exception ignore) {}
}

This is just an example... There are other ways to achieve the same (see also Peter's answer)

like image 30
Lukas Eder Avatar answered Oct 06 '22 05:10

Lukas Eder