Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

java static initialization with inheritance

public class Main {

    public static void main(String[] args) {
        System.out.println(B.x);
    }

}
class A {
    public static String x = "x";
}
class B extends A {
    static {
        System.out.print("Inside B.");
    }
}

Question: Why output will be: x. But not: Inside B.x

like image 553
Taras Koval Avatar asked Nov 20 '12 14:11

Taras Koval


People also ask

Is static block inherited in Java?

No,They never participates in inheritance. because staticblock is used for initializing static data member similarly instance is for initializing instance datamembers. Static block in java is executed before main method. If we declare a Static block in java class it is executed when class loads.

What is static initialization in Java?

A Static Initialization Block in Java is a block that runs before the main( ) method in Java. Java does not care if this block is written after the main( ) method or before the main( ) method, it will be executed before the main method( ) regardless.

Can static block override in Java?

One can not override a static block as the non-static else compile-time error will be generated. Non-static block can not be overridden as a static block.

How do you inherit a static class in Java?

Static methods in Java are inherited, but can not be overridden. If you declare the same method in a subclass, you hide the superclass method instead of overriding it. Static methods are not polymorphic. At the compile time, the static method will be statically linked.


3 Answers

The reference to B.x issues the following bytecode:

getstatic       #3   <Field int B.x>

According to Java Virtual Machine Spec

The Java virtual machine instructions anewarray, checkcast, getfield, getstatic, instanceof, invokedynamic, invokeinterface, invokespecial, invokestatic, invokevirtual, ldc, ldc_w, multianewarray, new, putfield, and putstatic make symbolic references to the runtime constant pool. Execution of any of these instructions requires resolution of its symbolic reference.

So the JVM should resolve the symbolic reference to B.x. The field resolution is specified like this:

To resolve an unresolved symbolic reference from D to a field in a class or interface C, the symbolic reference to C given by the field reference must first be resolved (§5.4.3.1).

...

When resolving a field reference, field resolution first attempts to look up the referenced field in C and its superclasses:

If C declares a field with the name and descriptor specified by the field reference, field lookup succeeds. The declared field is the result of the field lookup.

Otherwise, field lookup is applied recursively to the direct superinterfaces of the specified class or interface C.

Otherwise, if C has a superclass S, field lookup is applied recursively to S.

Otherwise, field lookup fails.

In other words the JVM will resolve B.x into A.x. This is why only A class needs to be loaded.

like image 152
ShyJ Avatar answered Oct 11 '22 14:10

ShyJ


Because B.x is actually A.x so only the A class needs to be loaded.

like image 40
Peter Lawrey Avatar answered Oct 11 '22 12:10

Peter Lawrey


§12.4 "Initialization of Classes and Interfaces" of The Java Language Specification, Java SE 7 Edition specifies that:

Initialization of a class consists of executing its static initializers and the initializers for static fields (class variables) declared in the class.

[…]

A reference to a static field (§8.3.1.1) causes initialization of only the class or interface that actually declares it, even though it might be referred to through the name of a subclass, a subinterface, or a class that implements an interface.

So although — contrary to claims in some of the answers above — class B does have to be loaded, in order to determine that B.x is declared in A, class B is not initialized (i.e., its static initializers are not actually run) until you do something more specific to B.

like image 28
ruakh Avatar answered Oct 11 '22 12:10

ruakh