I have a problem which I can not understand for the life of me. Why do I get a null pointer here?
In principle I have three class. A singleton class, a factory class and a main. In the Main I call the Singleton class once and let me output something.
Then I call a static method on the factory. Within this factory class there is a static block, which in turn accesses the singleton class. At this moment, however, the instance of the singleton class is null.
I don't really understand this, because with the debugger I also see that the variable is null, but the flow of the calls is actually as expected.
Main.java
package testing;
public class Main {
public static void main(String[] args) {
Singleton.getInstance().getValue();
Factory.build();
}
}
Singleton.java
package testing;
public class Singleton {
private static final Singleton INSTANCE = new Singleton();
private String value;
public static Singleton getInstance() {
return INSTANCE;
}
private Singleton() {
configureSingleton();
Factory.build();
}
private void configureSingleton() {
value = "TEST";
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
Factory.java
package testing;
public class Factory {
static {
Singleton instance = Singleton.getInstance();
System.out.println(instance.getValue());
}
private Factory() {
}
public static void build() {
System.out.println("Building now");
}
}
The problem is that you are calling Factory.build(); inside of the Singleton constructor. There could be a problem with the sequence of execution.
In particular: Factory.build(); is called before the assignment to INSTANCE happens.
There is no point in using a method that is synchronized and does lazy loading. We know that code within the static block and static fields will be initialized when the class is loaded, and according to this answer, classes will only be loaded when you access a static field or invoke a static method on the Singleton. By accessing static fields/methods in @aran's answer, you are loading the class, therefore causing initialization. This is the same as calling getInstance() to test if lazy loading works, which does not make sense.
You could, use reflection on the system classloader to test if the class will be loaded, but @aran thinks it involves a "custom classloader". The more idiomatic approach would be to include a static block on the class that prints a text. See if it will print the text out:
public class Main {
public static void main(String[] args) {
System.out.println("Hello, world!");
}
}
class Singleton {
public static Singleton INSTANCE = new Singleton();
private Singleton() {}
static {
System.out.println("This should not happen.");
}
}
More detailed answer and how @aran's answer is not the root cause of the problem:
Factory.build()Factory.build in the constructor returns, the values is then assigned to the INSTANCE field.The problem is Factory.build uses the INSTANCE field, before it is assigned (i.e. after the constructor returns.)
In general, private static Singleton INSTANCE = new Singleton(); works. Writing lazy loading yourself is more verbose, but not necessary. If you have other static methods that you will call during execution (which you shouldn't have because you have a singleton), then sure, @aran's answer will work for you.
Please note that native implementations do need synchronization because it is not provided from the runtime. However, when you are operating on the JVM, class loading is already synchronized and initializing variable during class load is the best approach if you don't have bad practices like having static members of a singleton other than the INSTANCE field.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With