Static Block in Java

Static Block in Java

It's a static initializer. It's executed when the class is loaded (or initialized, to be precise, but you usually don't notice the difference).

It can be thought of as a "class constructor".

Note that there are also instance initializers, which look the same, except that they don't have the static keyword. Those are run in addition to the code in the constructor when a new instance of the object is created.

Static block and a Normal Block

Static block are executed when classes are loaded where as normal blocks are executed when an instance of the class enclosing the block is created.

Just for the record prior to java 7 static blocks were executed before main() method was searched in the project. But from java 7 main() is first looked up. So you will get an error if you don't have main.So saying I know the static blocks run before main is a bit ambiguous. main() method is looked up prior to executing static blocks but the main execution will start after the static blocks are handled.

Also non static blocks are executed before the corresponding constructor is invoked.
For example

public class Tester {

{
System.out.println("In some random block");
}

static {
System.out.println("In static block");
}

public Tester() {
System.out.println("Constructor");
}


public static void main(String args[]) {
Tester t = new Tester();
}


}

will print

In static block
In some random block
Constructor

How to execute a static block for multiple times in java

Executing a Static Block can be Achieved by using Custom Class Loader.

ClassReload.java

    Class<?> load = ClassLoader.getSystemClassLoader().loadClass("com.Hello");
//Assume Hello class is in "com" package
load.newInstance().toString();
URL[] urls = { load.getProtectionDomain().getCodeSource().getLocation() };
ClassLoader delegateParent = load.getClassLoader().getParent();
try (URLClassLoader cl = new URLClassLoader(urls, delegateParent)) {
Class<?> reloaded = cl.loadClass(load.getName());
reloaded.newInstance().toString();
}
}
}

Refer Oracle Document for URLClassLoader

Can one force execution of the static blocks of all the files in the application?

This is not possible, since the VM will never attempt to load a class that isn't required by the code path traversed on its own. There are some obvious and some obscure reasons why its done that way.

Rule of thumb is: If there is no dependency to a class that is reachable (through code) from the programs entry point, then that class will never be loaded. Although reachable is quite lose, e.g. a reference can be established by just knowing a class' name (e.g. from a configuration file) and accessing that class with e.g. Class.forName().

What you cannot achieve is just dropping a class into the class path and have that class automagically become an additional entry point (which executing any static code without a cause from the main (and only) entry point would classify as).

Difference between the static initializer block and regular static initialization

For your example, there is no difference. But as you can see,

public static String myString = "Hello World!";

can only accept an expression to initialize the variable. However, in a static initializer (JLS 8.7), any number of statements may be executed. E.g. it's possible to do this:

static
{
myString = "Hello";
myString += " ";
myString += "World";
}

For your example, there's obviously no need to do that, but it's possible for the initialization of a variable to take more than an expression, perhaps many statements, so Java made static initializers.

what is the difference between Initializing a static object inside static block and outside?

In your examples mentioned above both the program is doing the same thing. So you can't judge what is difference between initializing static object and static block. Static block will be called only once at the time of loading the class by the JVM. Purpose of static block is to initialize the static variables and calling static methods. Remember one thing,initialize before you use any resources and for that this is one option which wil be called even before calling the constructor of the class. If you have the requirement to initialize the static variables at the time of loading the class or calling the methods at the time of loading the class to initialize something then in that case static block will be helpful. Here is the example of creating the static object and initializing it in static block.

private static List<String> arrList = new ArrayList<>();
static{
arrList.add("Hello");
arrList.add("World!!!");
}

Necessity of static block in Java

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
}
};

What's the C++ idiom equivalent to the Java static block?

You can have static blocks in C++ as well - outside classes.

It turns out we can implement a Java-style static block, albeit outside of a class rather than inside it, i.e. at translation unit scope. The implementation is a bit ugly under the hood, but when used it's quite elegant!

Downloadable version

There's now a GitHub repo for the solution, containing a single header file: static_block.hpp.

Usage

If you write:

static_block {
std::cout << "Hello static block world!\n";
}

this code will run before your main(). And you can initialize static variables or do whatever else you like. So you can place such a block in your class' .cpp implementation file.

Notes:

  • You must surround your static block code with curly braces.
  • The relative order of execution of static code is not guaranteed in C++.

Implementation

The static block implementation involves a dummy variable initialized statically with a function. Your static block is actually the body of that function. To ensure we don't collide with some other dummy variable (e.g. from another static block - or anywhere else), we need a bit of macro machinery.

#define CONCATENATE(s1, s2) s1##s2
#define EXPAND_THEN_CONCATENATE(s1, s2) CONCATENATE(s1, s2)
#ifdef __COUNTER__
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __COUNTER__)
#else
#define UNIQUE_IDENTIFIER(prefix) EXPAND_THEN_CONCATENATE(prefix, __LINE__)
#endif // __COUNTER__
#ifdef _MSC_VER
#define _UNUSED
#else
#define _UNUSED __attribute((unused))
#endif // _MSC_VER

and here is the macro work to put things together:

#define static_block STATIC_BLOCK_IMPL1(UNIQUE_IDENTIFIER(_static_block_))

#define STATIC_BLOCK_IMPL1(prefix) \
STATIC_BLOCK_IMPL2(CONCATENATE(prefix,_fn),CONCATENATE(prefix,_var))

#define STATIC_BLOCK_IMPL2(function_name,var_name) \
static void function_name(); \
static int var_name _UNUSED = (function_name(), 0) ; \
static void function_name()

Notes:

  • Some compilers do not support __COUNTER__ - it's not part of the C++ standard; in those cases the code above uses __LINE__, which works too. GCC and Clang do support __COUNTER__.
  • This is C++98; you don't need any C++11/14/17 constructs. However, it's not valid C, despite not using any classes or methods.
  • The __attribute ((unused)) might be dropped, or replaced with [[unused]] if you have a C++11 compiler which doesn't like the GCC-style unused extension.
  • This does not avert or help with the static initialization order fiasco, since while you know your static block will execute before main(), you are not guaranteed when exactly that happens relative to other static initializations.

Live Demo

Static Initialization Blocks

The non-static block:

{
// Do Something...
}

Gets called every time an instance of the class is constructed. The static block only gets called once, when the class itself is initialized, no matter how many objects of that type you create.

Example:

public class Test {

static{
System.out.println("Static");
}

{
System.out.println("Non-static block");
}

public static void main(String[] args) {
Test t = new Test();
Test t2 = new Test();
}
}

This prints:

Static
Non-static block
Non-static block

Why static block is not executed

A class's static initialization normally happens immediately before
the first time one of the following events occur:

  • an instance of the class is created,
  • a static method of the class is invoked,
  • a static field of the class is assigned,
  • a non-constant static field is used, or [...]

You are currently not doing any of the above.
So, by replacing

Class<?> class1 = A.class;
System.out.println(class1);

with this for example

A object = new A();

will give you your result.



Related Topics



Leave a reply



Submit