We know that “Java Virtual Machine Specification” chapter 5.5 Initialization ^(1)^ strictly stipulates that there are only six situations where the class must be initialized immediately:

  • Encountered new (instantiated object), getstatic (read a class static field which is not modified by final or does not put the result into the constant pool at compile time), putstatic (set a class static field which is not modified by final or does not put the result into the constant pool at compile time) or invokestatic (calling a static method of a class) these four bytecode instructions, if the class has not been initialized, initialization needs to be triggered.
  • Use the methods of the java.lang.reflect package to make reflective calls on types
  • the parent class has not been initialized
  • When the virtual machine starts, the user needs to specify a main class (main) to be executed
  • When using the dynamic language support newly added by java7, if the final analysis result of a MthodHandle instance is REF_getStatic, REF_putstatic, REF_invokestatic, REF_newInvokeSpecial four types of method handles
  • An interface defines the interface method modified by default, and the implementation class of the interface is initialized at the same time

In addition, all reference types do not trigger initialization:

Subclass references parent class

Referring to a static field of a superclass through a subclass does not cause the subclass to be initialized:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.demo;

class Super{
static {System.out.println("Super");}
public static int value = 1;
}
class Sub extends Super{
static{System.out.println("Sub");}
}

public class SomeName{
public static void main(String[] args){
System.out.println(Sub.value);
}
}

What happens in the end? It will output “Super” first, and then the value of “value”.

For static fields, only the class that directly defines this field will be initialized, so the static field of the parent class is referenced through the subclass, and only the parent class will be initialized.

Array reference class

Referencing a class through an array definition does not trigger initialization of this class

1
2
3
4
5
6
public class SomeName{
public static void main(String[] args){
Sub[] sp = new Sub[5];
}
}

What happens in the end?

nothing.

It can be seen that the Sub class has not been initialized. But this code triggers the initialization phase of another class named “[Lcom.example.demo.Sub”. This thing is automatically generated by the virtual machine and a subclass directly inherited from Object , and the creation action is triggered by the bytecode instruction anewarray (that is, creating a new reference array).

The one-dimensional array represented by this class, users can only directly use the length property modified as public and the clone method. Of course, the properties and methods used in the array are all implemented in this class. This is because Java wraps the access to the array elements (it is the movement of the array pointer in C), which is why Java detects that the array is out of bounds and throws an ArrayIndexOutOfBoundsException instead of an illegal memory access like C.

To be precise, Java’s out-of-bounds check is not encapsulated in the class for array element access, but encapsulated in xaload (array elements pushed onto the stack) and xastore (array operations) bytecode instructions for array access.

Constant pool reference

Constants will be stored in the constant pool of the calling class during the compilation phase, and essentially there is no direct reference to the class that defines the constant

1
2
3
4
5
6
7
8
9
10
11
class Super{
static {System.out.println("Super");}
public static final String HELLO = "Hello";
}


public class SomeName{
public static void main(String[] args){
System.out.println(Super.HELLO);
}
}

The code here also does not output “Super” after running.

The constant value of hello has actually been converted into a reference of the SomeName class to its own constant pool during the compilation phase, so the two of them have nothing to do with each other.

Interface

Interfaces are a little different than classes. In fact, the interface also has an initialization process, but the interface cannot use static code blocks to output initialization information like a class. The compiler will generate a ““ class constructor for the interface to initialize the member variables defined in the interface. and:

The interface does not require all parent interfaces to be initialized, only when it is used will it be initialized.


Reference

(1) Yellin, F. and Lindholm, T., 1996. The java virtual machine specification.