0

I was testing java's "statics" a bit and found some things I don't get. Look at these codes:

public class X {
    public static int staticInit = 0;
    public static int staticInitRe = 0;
    public static int classicInitRe = 0;
}

public class Y extends X {
    public static int staticInitRe;
    public static int classicInitRe = 1;
    static {
        staticInitRe = 1;
        staticInit = 1;
    }
}

(where "Re" stands for "redeclared")

I made two Main classes for printing and loading

1.

public class Main {
    public static void main(String[] args) {
        System.out.println("staticInit X: "+X.staticInit);
        System.out.println("staticInitRe X: "+X.staticInitRe);
        System.out.println("classicInitRe X: "+X.classicInitRe);
        System.out.println("");

        System.out.println("staticInit Y: "+Y.staticInit);
        System.out.println("staticInitRe Y: "+Y.staticInitRe);
        System.out.println("classicInitRe Y: "+Y.classicInitRe);
        System.out.println("");

        System.out.println("staticInit X: "+X.staticInit);
        System.out.println("staticInitRe X: "+X.staticInitRe);
        System.out.println("classicInitRe X: "+X.classicInitRe);
        System.out.println("");

        System.out.println("staticInit Y: "+Y.staticInit);
        System.out.println("staticInitRe Y: "+Y.staticInitRe);
        System.out.println("classicInitRe Y: "+Y.classicInitRe);
        System.out.println("");

    }
}

output:

staticInit X: 0
staticInitRe X: 0
classicInitRe X: 0

staticInit Y: 0
staticInitRe Y: 1
classicInitRe Y: 1

staticInit X: 1
staticInitRe X: 0
classicInitRe X: 0

staticInit Y: 1
staticInitRe Y: 1
classicInitRe Y: 1

2.

public class Main {
    public static void main(String[] args) {
        System.out.println("staticInit X: "+X.staticInit);
        System.out.println("");

        System.out.println("staticInit Y: "+Y.staticInit);
        System.out.println("");

        System.out.println("staticInit X: "+X.staticInit);
        System.out.println("");

        System.out.println("staticInit Y: "+Y.staticInit);
        System.out.println("");

    }
}

output:

staticInit X: 0

staticInit Y: 0

staticInit X: 0

staticInit Y: 0

I don't understand what happens with the staticInit variable. In the output of the first snippet, I think it should be respectively 0, 1, 0, 1 or 0, 1, 1, 1, not 0, 0, 1, 1.

I also don't get why in the second snippet it changes to 0, 0, 0, 0 after removing prints of the other variables.

Vadim Kotov
  • 8,084
  • 8
  • 48
  • 62
radrow
  • 6,419
  • 4
  • 26
  • 53

1 Answers1

3

staticInit is a static variable of class X. Therefore, when you access it, only class X is initialized. This is true even when you access it via Y.staticInit. Y.staticInit and X.staticInit are the same variable.

Only when you access the first static variables of Y (Y.staticInitRe in your first snippet), class Y is initialized, which also changes the value of X.staticInit to 1.

On the other hand, X.staticInitRe and Y.staticInitRe are different variables and X.classicInitRe and Y.classicInitRe are different variables.

The first snippet :

    System.out.println("staticInit X: "+X.staticInit); // X is initialized. All all of its 
                                                       // variables are initialized to 0
    System.out.println("staticInitRe X: "+X.staticInitRe);
    System.out.println("classicInitRe X: "+X.classicInitRe);
    System.out.println("");

    System.out.println("staticInit Y: "+Y.staticInit); // Y is not initialized yet
    System.out.println("staticInitRe Y: "+Y.staticInitRe); // Y is initialized: 
                                                           // Y.staticInitRe, 
                                                           // Y.classicInitRe and 
                                                           // X.staticInit are assigned 1
                                                           // before this String is output
    System.out.println("classicInitRe Y: "+Y.classicInitRe);
    System.out.println("");

    System.out.println("staticInit X: "+X.staticInit); // was changed to 1 by Y's
                                                       // static initializer
    System.out.println("staticInitRe X: "+X.staticInitRe); // remains 0
    System.out.println("classicInitRe X: "+X.classicInitRe); // remains 0
    System.out.println("");

    System.out.println("staticInit Y: "+Y.staticInit);
    System.out.println("staticInitRe Y: "+Y.staticInitRe);
    System.out.println("classicInitRe Y: "+Y.classicInitRe);
    System.out.println("");

The second snippet doesn't access any variables or methods of class Y, so class Y is not initialized, and X.staticInit remains 0.

JLS 12.4.1. specifies when a class is initialized:

12.4.1. When Initialization Occurs

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.

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

Since Y.staticInit is not declared in Y, using that field doesn't initialize class Y.

Eran
  • 387,369
  • 54
  • 702
  • 768