I didn’t get a complete understanding of static constructors in Java. If it is allowed, why it is allowed? In what scenarios would you use it? What purpose would it serve? Can someone give me a simple example please?
2
Strictly speaking, Java does not have static constructors because a constructor, by definition, cannot be static. What you are referring to is called a “static initialization block.” A constructor implies that you are constructing an object. You cannot have constructor for a class because a class is not an instance of itself. It is simply a class.
All nit-picking aside, a static initialization block is used to initialize complex static (or class-level) fields for a class. Usually these are used to initialize things that either cannot be initialized in one line, or require that some other object (which may or may not be in the class in which the static block is implemented) be initialized first.
Basically, one might use them to tell the class “Hey, set variable A to this value FIRST, then, once that’s done, use A’s value to initialize B.” Since Java requires that standard field initialization be done either within a constructor or method, or via the call of a constructor or method (unless it is a literal), these can be a convenient method for initializing complex, static objects.
Static initialization blocks are not needed all too often, and generally should be avoided unless they have a real use. Don’t get me wrong, they have their place in Java, but like many other things (such as break, return, switch, and goto statements) they can be easily over-used, which reduces their readability and the maintainability of the code-base they are used in.
A brief example of a static initialization block being used would be the following (as per the excellent explanation of static initialization blocks found here):
Code:
public class StaticExample{
static {
System.out.println("This is first static block");
}
public StaticExample(){
System.out.println("This is constructor");
}
public static String staticString = "Static Variable";
static {
System.out.println("This is second static block and "
+ staticString);
}
public static void main(String[] args){
StaticExample statEx = new StaticExample();
StaticExample.staticMethod2();
}
static {
staticMethod();
System.out.println("This is third static block");
}
public static void staticMethod() {
System.out.println("This is static method");
}
public static void staticMethod2() {
System.out.println("This is static method2");
}
}
Output:
This is first static block
This is second static block and Static Variable
This is static method
This is third static block
This is constructor
This is static method2
Some instances they list when static blocks can be useful:
- If you’re loading drivers and other items into the namespace. For ex, Class class has a static block where it registers the natives.
- If you need to do computation in order to initialize your static variables,you can declare a static block which gets executed exactly once,when the class is first loaded.
- Security related issues or logging related tasks
Some reasons NOT to use static blocks (in other situations):
- There is a limitation of JVM that a static initializer block should not exceed 64K.
- You cannot throw Checked Exceptions.
- You cannot use the
this
keyword since there is no instance. - You shouldn’t try to access super since there is no such a thing for static blocks.
- You should not return anything from this block.
- Static blocks make testing a nightmare.
I should note: While some languages (such as C#) may have syntax for “constructors” that are static, those “constructors” function much the same way that static initialization blocks do in Java, and are seen by many (myself included) as misnomers in the language, given the basic concept of an OOP constructor.
2
it is used to initialize fields that is harder than simply assigning it:
public class Example{
public final static Map<String, String> preFilledField;
static{
Map<String, String> tmp = new HashMap<>();
//fill map
preFilledField = Collections.unmodifiableMap(tmp);
}
}
it is not possible to fill a map on initialization (unless you use the anonymous subclass hack) so this is the best way to guarantee it is filled before first use
You can also do this to catch checked exceptions when initializing
1
Gurgadurgen’s answer is probably what you’re looking for, but I’ll just add a couple of other points that are sometimes neglected when someone wants a “static constructor”.
If you want a static method that creates an instance of your class, you can create a static method that simply invokes the class’s constructor.
public class Example
{
/** Static method to create an instance. */
public static Example build()
{ return new Example() ; }
/** A field of each instance. */
private String stuff ;
/** The class's actual constructor. */
public Example()
{ stuff = new String() ; }
public String getStuff()
{ return this.stuff ; }
/**
* Mutator for "stuff" property. By convention this returns "void"
* but you might want to return the object itself, to support the
* sort of chained invocations that are becoming trendy now. You'll
* see the stylistic benefits of chaining later in this example.
*/
public Example setStuff( String newStuff )
{
this.stuff = newStuff ;
return this ;
}
}
public class ExampleTest
{
public static void main( String[] args )
{
// The usual instance model.
Example first = new Example() ;
System.out.println( first.setStuff("stuff").getStuff() ) ;
// Using your static method to construct an instance:
Example second = Example.build() ;
System.out.println( second.setStuff("more stuff").getStuff() ) ;
// Chaining all the invocations at once:
System.out.println( Example.build().setStuff("even more stuff").getStuff() ) ;
}
}
This produces the output:
stuff
more stuff
even more stuff
The other reason to make a static method to construct an instance is the case when you want to ensure that exactly one instance of your class exists at any given time; this is called a singleton. By convention, such a class would provide a static method called getInstance()
to get the one and only instance that is treated as a “singleton”.
public class SingletonExample extends Example
{
// Note: This extends my previous example, which has a "stuff"
// property, and a trivial constructor.
/** The singleton instance, statically initialized as null. */
private static SingletonExample singleton = null ;
/**
* The static accessor for the singleton. If no instance exists,
* then it will be created; otherwise, the one that already exists
* will be returned.
*/
public static SingletonExample getInstance()
{
if( singleton == null )
singleton = new SingletonExample() ;
return singleton ;
}
}
public class SingletonExampleTest
{
public static void main( String[] args )
{
System.out.println( SingletonExample.getInstance().setStuff("stuff").getStuff() ) ;
// You could still create instances of this class normally if you want to.
SingletonExample otherstuff = new SingletonExample() ;
otherstuff.setStuff("other stuff") ;
// But watch what happens to this.
System.out.println( SingletonExample.getInstance().getStuff() ) ;
System.out.println( otherstuff.getStuff() ) ;
// Now we show what happens when you start modifying the singleton.
SingletonExample theoneandonly = SingletonExample.getInstance() ;
theoneandonly.setStuff("changed stuff") ;
System.out.println( SingletonExample.getInstance().getStuff() ) ;
}
}
This produces the following.
stuff
stuff
other stuff
changed stuff
By storing a reference to the singleton, and then modifying it, the next call to getInstance()
gets that modified singleton.
It’s tempting to use singletons as a way to start creating global variables for your application. In some contexts this can be useful, but it can also get you into trouble. In particular I ran into an interesting bug while developing an Android app, where singleton instances could get lost. Jumping from one activity to another can sometimes lead the JVM to use a new “class loader” which won’t know about the singleton that was stored statically by a previous class loader.
While I understand that there are many who see the notion of a “static constructor” as a misnomer, I do not believe that to be the case. The issue is in the process of constructing both classes and their instance objects. It’s been stated in other threads that construction of the class is the job of the compiler. Even in Java, this is only half true.
The compiler constructs a scaffold for each class definition. The scaffold contains metadata about the class and what instances should have in them at the time of construction. If a class defines a field that is assigned a constant primitive value, then that value is included in the scaffold by the compiler. For any other value types being assigned, the compiler generates an initialization routine that is to be run 1 time, before the creation of the first class instance, that updates the scaffold with the proper values. This update cannot be done by the compiler.
Since this one-time update to the scaffold is often a critical prerequisite to the proper functioning of the instance constructors, it is also reasonable to call it a type of constructor. This is why in common OO languages that support the concept, it is called a static constructor. The concept behind the static initialization blocks in Java is little more than a semantic change to keep in line with the notion that a Java programmer should be both system and implementation agnostic.
As other answers have said, you can write static methods that construct an object. This gets round the lack of named constructors in Java (and many other languages. Delphi does support named constructors). You can play with the types and order of parameters but this can lead to unclear and fragile code.
For instance, we could invent a scenario where your object can be constructed from an XML string or a JSON string. You could write methods like:
static MyObject createFromXml(String xml);
static MyObject createFromJson(String json);
I’ve used this very occasionally as an alternative to a parameterless constructor with named initialisation methods:
MyObject myObject = new MyObject();
myObject.loadXml(xml).
You could look upon a static create method as implementing the builder pattern inside your class.
1
You can view the “static” section like a class level constructor use to initialize class properties (static in java). The same as the “normal” constructor its used to initialize instance level properties.