javabytecodestatic-block

What is happening with more than one static block in Java byte-code?


Here’s a very basic application in Java, containing only one class. In that class, there is one main method and two static blocks.

class Test {
    public static void main(String args[]) {
        System.out.println("Main");
    }

    static {
        int a = 10;
    }

    static {
        int a = 20;
    }
}

And here’s the bytecode produced by compiling this application. I don’t understand what has happened with the static blocks:

static {};
    descriptor: ()V
    flags: ACC_STATIC
    Code:
      stack=1, locals=1, args_size=0
         0: bipush        10
         2: istore_0
         3: bipush        20
         5: istore_0
         6: return
      LineNumberTable:
        line 34: 0
        line 37: 3
        line 38: 6

My question is: where is the second static block? If they merge, then how can the JVM differentiate between variables contained by both blocks, because both blocks have variables with same name and type?


Solution

  • At the bytecode level, there is only one static initializer method per class, named <clinit>. All of the static initializers at the Java level will be compiled into a single method. (This includes both static{} blocks and any static field initialized with a non constant expression, i.e. static Foo foo = bar())

    As far as how the JVM differentiates between the variables, it doesn't. Bytecode operates at a lower level of abstraction than Java source code. There are no local variables, only a stack and a table of slots that can hold values. The JVM doesn't need to know which values is which to execute your code, it just does what the bytecode says.

    The only time it becomes relevant is if you want the metadata for debugging, reflection, or the like. By default, the compiler will include metadata that says which local variable each slot in the bytecode corresponds too, if any. In a case like this, each slot is used by multiple local variables, so it stores the range of the bytecode during which the slot holds the value for each source level local variable.

    Anyway, this is all for static initializers. Non static initializers don't exist at the bytecode level at all. Instead, all of the initializers are concatenated and inlined into every constructor (<init> method of the class) that calls a superconstructor. This means that the code may appear more than once.