Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Static Field Initialization

I have just spent half an hour figuring this thing out, I have managed to fix my code, but I don't fully understand what is going on and wondered if someone could shed some light on it.

I have a utils type class, that contains a few static fields (a database connection endpoint for example) that are used by various other programs depending on the task at hand. Essentially a library.

This is how it looked previously (while still broken);

//DBUtils.java
public final class DBUtils {

    private static DBConnection myDBConnection = spawnDBConnection();
    private static DBIndex myDBIndex = null;

    private static DBConnection spawnDBConnection() {
        //connect to the database
        //assign a value to myDBIndex (by calling a method on the DBConnection object) <- IMPORTANT
        //myDbIndex NOT NULL HERE
        System.out.println("database connection completed");
        //return the DBConnection object
    }

    public static searchDB(String name) {
        //use the myDBIndex to find a row and return it
    }
}

So briefly, I am using the static spawnDBConnection() method to assign a value to both myDBConnection and myDBIndex. This works perfectly, the first output line from my program is always "database connection completed", neither myDBConnection or myDBIndex are null at the end of the spawnDBConnection() method, everything is as it should be.

My external program looks like this;

//DoSomethingUsefulWithTheDatabase.java
public final class DoSomethingUsefulWithTheDatabase {

    public static void main(String args[]) {
        DBUtils.searchDB("John Smith"); //fails with NullPointerException on myDBIndex!
    }
}

This call to searchDB happens after the spawnDBConnection has finished, I have used the standard output extensively to show this. However, once inside the searchDB method, the value of myDBIndex is null! It's a static field, and it was not null by the end of spawnDBConnection, no other assignments have been made, and now it's null :(

The simple fix was to remove the "= null" so the field declaration now looks like;

private static DBIndex myDBIndex;

Why did that make a difference? I'm thoroughly confused by this one.

like image 908
lynks Avatar asked Jul 24 '12 12:07

lynks


People also ask

How do you initialize a static field in Java?

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.

What is static initialization in Java?

A Static Initialization Block in Java is a block that runs before the main( ) method in Java. Java does not care if this block is written after the main( ) method or before the main( ) method, it will be executed before the main method( ) regardless.

Do static variables need to be initialized?

Static variables are initialized only once. Compiler persist the variable till the end of the program. Static variable can be defined inside or outside the function. They are local to the block.

Can static variables be re initialized in Java?

Declaring variables only as static can lead to change in their values by one or more instances of a class in which it is declared. Declaring them as static final will help you to create a CONSTANT. Only one copy of variable exists which can't be reinitialize.


2 Answers

That's because the assignment of null to myDBIndex is done after

private static DBConnection myDBConnection = spawnDBConnection();

e.g. overrides the assignment in spawnDBConnection

The sequence is:

  1. declare the fields myDBConnection, myDBIndex
  2. Initialize myDBConnection = spawnDBConnection();

    Which includes calling spawnDBConnection and assignment of the return value to myDBConnection

  3. Initialize myDBIndex (with null)

In your second example, the 3rd step does not exist.

like image 140
MByD Avatar answered Oct 21 '22 05:10

MByD


Why did that make a difference? I'm thoroughly confused by this one.

The initializer for spawnDBConnection was running, then the initializer for myDBIndex was running. The initializer for myDBIndex set the value to null. As this happened after spawnDBConnection set it to a non-null value, the final result was that it was null.

Try not to do this - it's odd for a method called by a static initializer to set other static variables.

like image 22
Jon Skeet Avatar answered Oct 21 '22 04:10

Jon Skeet