java static initialization with inheritance
Asked Answered
C

5

17
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

Conundrum answered 20/11, 2012 at 14:19 Comment(0)
R
11

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.

Ruby answered 20/11, 2012 at 14:27 Comment(3)
Ok, but where it's behaviour is described, I mean in spec?Conundrum
It's not true. For example, you can add static field x to B and it will be printed even if you don't recompile Main.Sinegold
@ShyJ: I didn't like your first answer but this is definitely the best answer now. +1Syrup
H
7

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

Hoarding answered 20/11, 2012 at 14:22 Comment(0)
M
4

§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.

Madonna answered 20/11, 2012 at 16:45 Comment(0)
Z
2

Class B extends A which has an public static variable x which you are accessing when you call B.x

If you expect Inside B. as out put you have to create an Object of that class. All the static code blocks are executed. or move that static code block to class A :-)

When JVM loads class it groups all the static blocks and execute them in the sequence they are declared.

EDIT (Source): The short answer is that statics are NOT inherited in Java. Rather, the static members declared in a class are (subject to "access" restrictions) directly visible in the namespace of derived classes, unless they "hidden" by declarations in the derived class.

So if the Static belongs to the Class only why does it trickle down to the derived class ? Shouldn't it just stay with the Class in which it was defined ?

Zoonosis answered 20/11, 2012 at 14:21 Comment(3)
Yes, but why static block is not executed.Conundrum
You don't have to create an object of that class to execute the static block. See my example belowSyrup
@Syrup I just told an way to achieve it any ways the question was why is example not executing Static Code block in derived class :-)Zoonosis
S
2

It doesn't actually need to load B until it accesses a static member of B directly. Note that this code:

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

    static class A {
        public static String x = "x";
    }

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

Will output:

x
Inside B.y

Because it doesn't need to load B until something in B is accessed.

Here's a good link on the subject. From the article, "And dont forget, this code will be executed when JVM loads the class. JVM combines all these blocks into one single static block and then executes. Here are a couple of points I like to mention: "

Syrup answered 20/11, 2012 at 14:33 Comment(2)
So this looks like compilator optimization, but compilator can be different. Is it described somewhere?Conundrum
@user1839039: I added a link for youSyrup

© 2022 - 2024 — McMap. All rights reserved.