Does calling a static method on a class in Java trigger the static initalization blocks to get executed?
Empirically, I’d say no. I have something like this:
public class Country {
static {
init();
List<Country> countries = DataSource.read(...); // get from a DAO
addCountries(countries);
}
private static Map<String, Country> allCountries = null;
private static void init() {
allCountries = new HashMap<String, Country>();
}
private static void addCountries(List<Country> countries) {
for (Country country : countries) {
if ((country.getISO() != null) && (country.getISO().length() > 0)) {
allCountries.put(country.getISO(), country);
}
}
}
public static Country findByISO(String cc) {
return allCountries.get(cc);
}
}
In the code using the class, I do something like:
Country country = Country.findByISO("RO");
The problem is that I get a NullPointerException because the map (allCountries) is not initialized. If I set up breakpoints in the static block I can see the map getting populated correctly, but it’s as if the static method has no knowledge of the initializer being executed.
Can anyone explain this behavior?
Update: I’ve added more detail to the code. It’s still not 1:1 (there are several maps in there and more logic), but I’ve explicitly looked at the declarations/references of allCountries and they are as listed above.
You can see the full initialization code here.
Update #2: I tried to simplify the code as much as possible and wrote it down on the fly. The actual code had the static variable declaration after the initializer. That caused it to reset the reference, as Jon pointed out in the answer below.
I modified the code in my post to reflect this, so it’s clearer for people who find the question. Sorry about the confusion everyone. I was just trying to make everyone’s life easier :).
Thanks for your answers!
You’re wrong.
From the JLS section 8.7:
Section 12.4.1 of the JLS states:
This is easily shown:
Your problem is in some part of the code that you didn’t show us. My guess is that you’re actually declaring a local variable, like this:
That hides the static variable, leaving the static variable null. If this is the case, just change it to an assignment instead of a declaration:
EDIT: One point worth noting – although you’ve got
init()as the very first line of your static initializer, if you’re actually doing anything else before then (possibly in other variable initializers) which calls out to another class, and that class calls back into yourCountryclass, then that code will be executed whileallCountriesis still null.EDIT: Okay, now we can see your real code, I’ve found the problem. Your post code has this:
But your real code has this:
There are two important differences here:
The combination of those is messing you up: the variable initializers aren’t all run before the static initializer – initialization occurs in textual order.
So you’re populating the collection… and then setting the reference to null.
Section 12.4.2 of the JLS guarantees it in step 9 of the initialization:
Demonstration code:
Output:
So the solution is either to get rid of the explicit assignment to null, or to move the declarations (and therefore initializers) to before the static initializer, or (my preference) both.