Reputation: 5153
I found that in Java, there is a feature called static block
, which includes code that is executed when a class is first loaded (I don't understand what 'loaded' means, does it mean initialized?). Is there any reason to do the initialization bit inside a static block and not in the constructor? I mean, even the constructor does the same thing, do all the necessary stuff when a class is first initialized. is there anything that the static block accomplishes which a constructor can't?
Upvotes: 60
Views: 35183
Reputation: 11
If you'd like to get a full understanding of the technical concept (in this scenario - the usage of static blocks in Java), you'd probably need to find the reference to this concept in a real application. Let me attach here a link to the repo of Gomoku game implementation where static block is used in "Board.java" class to initialize a static field "Location".
public class Board {
public static final Iterable<Location> LOCATIONS;
// set up LOCATIONS
static {
ArrayList<Location> l = new ArrayList<Location>(NUM_ROWS * NUM_COLS);
for (int r = 0; r < NUM_ROWS; r++)
for (int c = 0; c < NUM_COLS; c++)
l.add(new Location(r,c));
LOCATIONS = l;
}
}
Upvotes: 0
Reputation: 322
Initializing static fields in the constructor is a big mistake. Yes, you can initialize static fields in the constructor. However, the static fields will reset their value every time an object is created.
public class StaticExample {
static int myStaticField;
public StaticExample(){
myStaticField = 10;
}
}
public class Solution {
public static void main(String[] args) {
StaticExample obj1 = new StaticExample();
StaticExample.myStaticField+= 80;
// this will print 90
System.out.println(StaticExample.myStaticField);
// creating new object will reset the static field
StaticExample obj2 = new StaticExample();
// this will print 10
System.out.println(StaticExample.myStaticField);
}
}
This is unexpected and unaccepted behavior for a static field. If you now change the initialization step from a constructor to a static block, you will get the correct values.
public class StaticExample {
static int myStaticField;
static {
myStaticField = 10;
}
}
public class Solution {
public static void main(String[] args) {
StaticExample obj1 = new StaticExample();
StaticExample.myStaticField+= 80;
// this will print 90
System.out.println(StaticExample.myStaticField);
// creating new object will NOT reset the static field
StaticExample obj2 = new StaticExample();
// this will print 90
System.out.println(StaticExample.myStaticField);
}
}
Upvotes: 0
Reputation: 234795
I first want to highlight one thing thing from your question:
the constructor does the same thing, do all the necessary stuff when a class is first initialized
This is incorrect. A constructor does all the initialization necessary when an instance of a class is created. No constructors execute when the class itself is first loaded into memory and initialized (unless an instance of the class happens to be created as part of the class initialization). This confusion (between initializing a class and initializing instances of the class) is probably why you are questioning the utility of static
blocks.
If a class has static members that require complex initialization, a static
block is the tool to use. Suppose you need a static map of some kind (the purpose is irrelevant here). You can declare it in-line like this:
public static final Map<String, String> initials = new HashMap<String, String>();
However, if you want to populate it once, you can't do that with an in-line declaration. For that, you need a static
block:
public static final Map<String, String> initials = new HashMap<String, String>();
static {
initials.put("AEN", "Alfred E. Newman");
// etc.
}
If you wanted to be even more protective, you can do this:
public static final Map<String, String> initials;
static {
Map<String, String> map = new HashMap<String, String>()
map.put("AEN", "Alfred E. Newman");
// etc.
initials = Collections.unmodifiableMap(map);
}
Note that you cannot initialize initials
in-line as an unmodifiable map because then you couldn't populate it! You also cannot do this in a constructor because simply calling one of the modifying methods (put
, etc.) will generate an exception.
To be fair, this is not a complete answer to your question. The static
block could still be eliminated by using a private static function:
public static final Map<String, String> initials = makeInitials();
private static Map<String, String> makeInitials() {
Map<String, String> map = new HashMap<String, String>()
map.put("AEN", "Alfred E. Newman");
// etc.
return Collections.unmodifiableMap(map);
}
Note, though, that this is not replacing a static
block with code in a constructor as you proposed! Also, this won't work if you need to initialize several static
fields in an interrelated way.
A case where a static
block would be awkward to replace would be a "coordinator" class that needs to initialize several other classes exactly once, especially awkward if it involves dependency injection.
public class Coordinator {
static {
WorkerClass1.init();
WorkerClass2.init(WorkerClass1.someInitializedValue);
// etc.
}
}
Particularly if you don't want to hard-wire any dependence into WorkerClass2
on WorkerClass1
, some sort of coordinator code like this is needed. This kind of stuff most definitely does not belong in a constructor.
Note that there is also something called an instance initializer block. It is an anonymous block of code that is run when each instance is created. (The syntax is just like a static
block, but without the static
keyword.) It is particularly useful for anonymous classes, because they cannot have named constructors. Here's a real-world example. Since (unfathomably) GZIPOutputStream
does not have a constructor or any api call with which you can specify a compression level, and the default compression level is none, you need to subclass GZIPOutputStream
to get any compression. You can always write an explicit subclass, but it can be more convenient to write an anonymous class:
OutputStream os = . . .;
OutputStream gzos = new GZIPOutputStream(os) {
{
// def is an inherited, protected field that does the actual compression
def = new Deflator(9, true); // maximum compression, no ZLIB header
}
};
Upvotes: 55
Reputation: 4706
One way you can understand static block is; It acts as a constructor. however, the difference between the two is static block instantiates class or static variables while constructor is used to instantiate object variables
Consider the following class
public class Part{
String name;
static String producer;
public Part(String name){
this.name = name;
}
static {
producer = "Boeing";
}
}
objects created from this class will have producer set to Boeing but their name is different depending on the argument passed. for instance
Part engine = new Part("JetEngine");
Part Wheel = new Part("JetWheel");
Upvotes: 1
Reputation: 31
The static block is useful over constructors when you do have to do some action even if no instances is still created. As example, for initializing a static variable with non static value.
Upvotes: 1
Reputation: 10997
Constructor is invoked while creating an instance of the class.
Static block is invoked when a classloader loads this class definition, so that we can initialize static members of this class. We should not be initializing static members from constructor as they are part of class definition not object
Upvotes: 18
Reputation: 86178
Static initializer will run if we initialize a class, this does not require that we instantiate a class. But the constructor is run only when we make an instance of the class.
For example:
class MyClass
{
static
{
System.out.println("I am static initializer");
}
MyClass()
{
System.out.println("I am constructor");
}
static void staticMethod()
{
System.out.println("I am static method");
}
}
If we run:
MyClass.staticMethod();
Output:
I am static initializer
I am static method
We never created an instance so the constructor is not called, but static initializer is called.
If we make an instance of a class, both static initilizer and the constructor run. No surprises.
MyClass x = new MyClass();
Output:
I am static initializer
I am constructor
Note that if we run:
MyClass x;
Output: (empty)
Declaring variable x
does not require MyClass
to be initialized, so static initializer does not run.
Upvotes: 10
Reputation: 53
The static block is useful when you want to initialize static fields.
Upvotes: 2
Reputation: 838156
The static initializer runs when the class is loaded even if you never create any objects of that type.
Upvotes: 7
Reputation: 909
static block does different thing than constructor . Basically there sre two different concepts.
static block initializes when class load into memory , it means when JVM read u'r byte code. Initialization can ne anything , it can be variable initialization or any thing else which should be shared by all objects of that class
whereas constructor initializes variable for that object only .
Upvotes: 3
Reputation: 1385
The static block is reqly useful when you do have to do some action even if no instances is still created. As example, for initializing a static variable with non static value.
Upvotes: 3
Reputation: 96385
They're two separate things. You use a constructor to initialize one instance of a class, the static initialization block initializes static members at the time that the class is loaded.
Upvotes: 3
Reputation: 198033
You can't initialize static variables with a constructor -- or at least you probably shouldn't, and it won't be particularly useful.
Especially when you're trying to initialize static constants that require significant logic to generate, that really ought to happen in a static block, not a constructor.
Upvotes: 5