12

The following Java code does not invoke the static initializer of class B. Why?

Code:

class A 
{
    static 
    {
        System.out.println("A static init");
    }

    public static void f() 
    {
        System.out.println("f() called");
    }
}

class B extends A 
{
    static 
    {
        System.out.println("B static init");
    }
}

public class App
{
    public static void main( String[] args)
    {
        B.f(); //invokestatic  #16                 // Method com/db/test/B.f:()V
    }
}

Program output:

A static init
f() called

Tested on JDK 1.8.0_25

Raedwald
  • 46,613
  • 43
  • 151
  • 237
Sergey Alaev
  • 3,851
  • 2
  • 20
  • 35
  • 1
    Possibly a duplicate of http://stackoverflow.com/questions/13475172/java-static-initialization-with-inheritance – h7r Feb 01 '15 at 18:35

2 Answers2

14

There is no such thing as "static constructor". It's a static initialization block, and it is only executed when the class is initialized. Since you are calling a static method of class A (even though you are referring to it via class B), there is no need to initialize class B. Calling B.f(); is the same as calling A.f();.

The static initialization block of class B will be executed if you create an instance of class B or access a static member/method of class B.

Here are the only conditions that trigger class initialization (JLS 12.4.1):

A class or interface type T will be initialized immediately before the first occurrence of any one of the following:

 T is a class and an instance of T is created.

 T is a class and a static method declared by T is invoked.

 A static field declared by T is assigned.

 A static field declared by T is used and the field is not a constant variable (§4.12.4).

 T is a top level class (§7.6), and an assert statement (§14.10) lexically nested within T (§8.1.3) is executed.
Eran
  • 387,369
  • 54
  • 702
  • 768
  • Addition: what happend if class B overrides f() ? – Niels Jan 13 '15 at 13:16
  • @Niels, there's no such thing as overriding on `static` methods. If there is a `static` method `f()` in `B`, then it will be called. – Konstantin Yovkov Jan 13 '15 at 13:17
  • @Niels You can't override a static method. If B would define its own static `f()` method, class B would be loaded and its static initialization block would be executed, and that `f()` method is the method that would be executed. In such case, A would also be loaded, since it's a super-class of B. – Eran Jan 13 '15 at 13:18
  • Would it be possible to call this static initializer? – Thomas Mar 07 '23 at 12:24
  • @Thomas The static initializer is called automatically. You can't call it explicitly. – Eran Mar 07 '23 at 13:14
  • How about this one: Class.forName(MyClass.class.getName()) Isn't this a proper way to make sure the initializer is called? – Thomas Mar 08 '23 at 15:18
5

Since only class A defines the method f(), class B is loaded but not initialized.

You could use java -verbose:class MyClassName to check this.

On a jdk6 / jdk 8 machine, this will be printed.

[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXXX]
[Loaded B from file://C:/XXXXXXX]
A static init
f() called

Class B will be initialized lazily but loaded greedily (since it is being referred).

Change your code to A.f(). Then you will see that B is not loaded.

[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXX]
A static init
f() called

Note : Class loading and initialization are 2 different things. Check documentation for Class.forName() for details.

TheLostMind
  • 35,966
  • 12
  • 68
  • 104
  • Do you know if B is guaranteed to get loaded, or could it be platform dependent? – Paul Boddington Jan 13 '15 at 13:34
  • 1
    @pbabcdefp - It will be VM (implementation) dependent. Some implementations will load `B` greedily, others might resolve the call to `A` directly thus not loading `B`. – TheLostMind Jan 13 '15 at 13:35