1

I think that only Base class is initialized when Derived.f() is called. Exactly like it happens when we have a (non-compile-time-constant) static field in Base, not static method. My doubt is only that JLS is not very clear on that.

class Base {
    static void f() {}
}

class Derived extends Base {

}

Derived.f(); // called legally from some other class

According to JLS (see below), it seems that only Base class is initialized. But do I read and understand JLS correctly?

I also know that in the case with (non-compile-time-constant) static fields only class where static field is defined is initialized (static initializers called):

class Base {
    static int x = 1;
}

class Derived extends Base {

}

//somewhere in some other class
int y = Derived.x;  // triggers only Base to be initialized

12.4.1. When Initialization Occurs (JLS)

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.

T is a class and 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.

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. BUT JLS DOES NOT STATE HERE THE SAME ABOUT STATIC METHODS THOUGH !

Besides, 12.4. Initialization of Classes and Interfaces says clearly:

Before a class is initialized, its direct superclass must be initialized

And an exclusion from this rule is given by JLS only for static fields, not static methods!

Initializing both Base and Derived seemingly would make sense - if f() uses any static fields inside its body, then Derived.f() will be using static fields of Derived (if any), and may use static fields inherited from Base (if Derived has none) - which makes sense to initialize both classes.

After all, simple test shows that only Base class is initialized:

class Base {
    static { System.out.println("Base init"); }

    static void f() {}
}

class Derived extends Base {
    static { System.out.println("Derived init"); }
}

public class Driver {
    public static void main(String[] args)  {
        Derived.f(); // Only "Base init" printed...
    }
}
Code Complete
  • 3,146
  • 1
  • 15
  • 38

1 Answers1

0

Perhaps the confusion is about how member variables, including static member variables, work in Java. Unlike methods, member variables in derived classes do not inherit their super class counterparts; they merely shadow them. Thus, if you have a variable foo in Base and a variable foo in Derived, then if you print that variable in Base you will get the version in Base, and if you print from Derived, you get the version in Derived.

public class MyTest {

    public static void main(String[] args) {

        Base.f();
        Derived.f();
    }
}

class Base {
    static void f() {
        System.out.println("bar = " + bar);
    }

    protected static int bar = 1;
}

class Derived extends Base {
    static void f() {
        System.out.println("bar = " + bar);
    }

    private static int bar = 2;
}

gives:

bar = 1
bar = 2

So, there is no reason to run the initializers in Derived when you call a static method in Base because Base could never directly access the variables in Derived.

Steve Brandli
  • 556
  • 4
  • 14