Static initializer not invoked for a derived class - java

The following Java code does not invoke the static initializer of class B. Why?
Code:
class A
{
static
{
System.out.println("A static init");
}
public static void f()
{
System.out.println("f() called");
}
}
class B extends A
{
static
{
System.out.println("B static init");
}
}
public class App
{
public static void main( String[] args)
{
B.f(); //invokestatic #16 // Method com/db/test/B.f:()V
}
}
Program output:
A static init
f() called
Tested on JDK 1.8.0_25

There is no such thing as "static constructor". It's a static initialization block, and it is only executed when the class is initialized. Since you are calling a static method of class A (even though you are referring to it via class B), there is no need to initialize class B. Calling B.f(); is the same as calling A.f();.
The static initialization block of class B will be executed if you create an instance of class B or access a static member/method of class B.
Here are the only conditions that trigger class initialization (JLS 12.4.1):
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.

Since only class A defines the method f(), class B is loaded but not initialized.
You could use java -verbose:class MyClassName to check this.
On a jdk6 / jdk 8 machine, this will be printed.
[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXXX]
[Loaded B from file://C:/XXXXXXX]
A static init
f() called
Class B will be initialized lazily but loaded greedily (since it is being referred).
Change your code to A.f(). Then you will see that B is not loaded.
[Loaded App from file:/C:/XXXX/]
[Loaded A from file:/C:/XXXXX]
A static init
f() called
Note : Class loading and initialization are 2 different things. Check documentation for Class.forName() for details.

Related

java- "new" operator in static method

I know this is reference variable which holds the reference for object and static method loads when the class is first accessed by class loader, either to create an instance, or to access a static method or field.
Why its not allowed for this but for instance itself? For e.g.
Class A{
public static void main(String... args){
this.method(); //not allowed
new A().method(); //allowed, how?
}
void method(){
System.out.println("Class A");
}
}
this.method(); //not allowed
You have no instance this in static context so you can't invoke method.
new A().method(); //allowed, how?
You have instance created by new operator so that you can invoke a method.
To invoke a method without having a real instance you have to declare it as static. i.e.:
static void method(){
System.out.println(“Class A”);
}
this will work when calling just method() and via instance:
public class A {
public static void main(String[] argv) {
method(); //works because method is static
new A().method(); //still ok, we can call static method using an instance
this.method(); //not allowed, there is no 'this' in static context
}
static void method(){
System.out.println("Class A");
}
}
static variables and instance variables follow the initialization order you mention when they are initialized in their declarations. Also static initializer blocks follow that order.
Methods (including constructors) on the other hand need no initialization at runtime. They are fully defined at compile-time and therefore exist and can be called as soon as the class is loaded, also before the initialization is complete. Therefore there is no problem in your main method instantiating the class (calling the default constructor) and calling a method that is declared later, as method is declared below main.
In addition, the main method is also only executed after any static initialization is complete.

Why is sub class' static code getting executed?

I have written the following code and created object for the super class.
class SuperClass{
static int a=2;
static int b(){
return 2;
}
int c(){
return 2;
}
SuperClass(){
System.out.println("Super");
}
static {
System.out.println("super");
}
}
public class Sub extends SuperClass{
Sub(){
System.out.println("Sub");
}
static {
System.out.println("sub");
}
static int b(){
return 3;
}
int c(){
return 3;
}
public static void main(String ax[]){
SuperClass f =new SuperClass();
System.out.println(f.c());
System.out.print(SuperClass.b());
}
}
When I checked the output, it is as follows:
super
sub
Super
2
2
I know that static block is executed only when object of the class is initialized or any static reference is made. But here, i did not make any of these to Sub class. then why do i see "sub" i.e. sub class' static block output?
I know that static block is executed only when object of the class is initialized or any static reference is made. But here, i did not make any of these to Sub class.
Your code doesn't, but in order for that main to run, Sub has to be loaded. So the static initializer for it is run.
E.g., I'm assuming you ran it like this:
java Sub
The java tool has to load Sub to call Sub.main. That's the static reference (access, really) causing the static initializer to run. (If you ran it in an IDE, the IDE will do the java tool part, but the result is the same.)
So here's what happened:
java triggers load of Sub
JVM has to load SuperClass in order to load Sub
So we see their static initializers run, in order (SuperClass, then Sub):
super
sub
java tool calls main
Code in main calls new SuperClass:
Super
Code in main calls f.c()
2
Code in main calls SuperClass.b:
2
As Holger helpfully points out, this is covered by the JVM specification in §5.5 - Initialization and the related §5.2 - Java Virtual Machine Startup:
Initialization of a class or interface consists of executing its class or interface initialization method (§2.9).
A class or interface C may be initialized only as a result of:
...
If C is a class, the initialization of one of its subclasses.
If C is a class, its designation as the initial class at Java Virtual Machine startup (§5.2).
That second-to-last bullet point covers SuperClass, and the last bullet point covers Sub.
Because your main() method is a member of Sub, that class needs to be loaded for your program to run.
In calling main, all the static initialisers are called, first in the super class, then the sub class.
That explains the output you observe.
static blocks are run when the class is loaded. usually that is because you call a constructor or static member. in this case, it is because you executed the main method (a static member).
side notes:
another edge case is calling Class.forName(className) to load a class.
you may also notice that the base class is loaded before the subclass.

Local class instance creation expression in a static-context

The JLS 15.9.2 tells us how to determine an enclosing instance:
Let C be the class being instantiated, and let i be the instance being created.
If C is an inner class, then i may have an immediately enclosing
instance (§8.1.3), determined as follows:
[...]
If C is a local class, then:
If C occurs in a static context, then i has no immediately enclosing
instance.
Otherwise, if the class instance creation expression occurs in a
static context, then a compile-time error occurs.
Otherwise, let O be the immediately enclosing class of C. Let n be an
integer such that O is the n'th lexically enclosing type declaration
of the class in which the class instance creation expression appears.
The immediately enclosing instance of i is the n'th lexically
enclosing instance of this.
I didn't get what the bolded case means. Let me provide the example I wasn't supposed to be compiled:
class A{
int a;
public static void main (String[] args) throws java.lang.Exception{
class Foo{
void bar(){
}
}
Foo f = new Foo(); //Instance creation expression occured in the static context
}
}
DEMO
What's wrong with that? Couldn't you provide an actual example describing the second point?
You should read these two lines :
If C occurs in a static context, then i has no immediately enclosing instance.
Otherwise, if the class instance creation expression occurs in a static context, then a compile-time error occurs.
Your case is the first case - you defined the class Foo in a static context (the main method), and therefore the instance f has no enclosing instance.
If, however, you'd define the class Foo outside the main method, and try to create the instance of Foo in the main method, you'll get an error, unless you change Foo to be a static class.
class A
{
int a;
class Foo
{
void bar()
{
}
}
public static void main (String[] args) throws java.lang.Exception
{
Foo f = new Foo(); // this should fail
}
}
I guess the following case is meant:
public class A {
public class B { /* ... */ }
public static void createB() {
new B(); // <<=== This should fail
}
}
The marked line should fail, since the inner class B is not static, so it requires en enclosing instance of A. There is no such enclosing instance, since the method createB() is static.
UPDATE: I mistook the question beeing about inner classes in general, which is what my example shows. In the context of Local Classes I also can't interpret the documentation.

Java why static prints out text first than method

Just wondering why static is always the one that will print out first rather than a method.
Code:
public class TestMe {
static {
System.out.println("D");
}
{
System.out.println("B");
}
public void printMe() {
System.out.println("Z");
}
public static void main(String []args) {
new TestMe().printMe();
}
}
Output:
D
B
Z
static blocks are executed when a class is first initialized (initialization of a class happens once it is loaded ) so they execute earlier than instance level blocks / methods (executed after creating an object)
You have two types of initializer block in your class
one is static initializer which is executed by the time the class is initialized
8.7. Static Initializers
A static initializer declared in a class is executed when the class is initialized
8.6. Instance Initializers
two is the Instance Initializers which is executed when instance of the class is already create
An instance initializer declared in a class is executed when an instance of the class is created
Those are from JLS documentation
So static initializer will be called directly when class is initialized vs Instance Initializers that is called when instance of that class is already created thus static initializer is executed first.
Because static blocks are executed when the class is loaded.
because that gets executed when class initializes it self
Also See
doc: Initializing Fields

Only super class is initialized even though static field is referenced using sub type

I am doing some research on JAVA initialization process.
Here is a good material for reference:
When a class is loaded and initialized in JVM
On this page there is rule says:
3) If Class initialization is triggered due to access of static field, only Class which has declared static field is initialized and it doesn't trigger initialization of super class or sub class even if static field is referenced by Type of Sub Class, Sub Interface or by implementation class of interface.
I really don't understand the idea. If the static field is referenced by Sub class, then this field of course need to create a sub class object or assigned by a Sub class object.
So, it definitely triggers Sub class initialization.
What's wrong with my interpretation?
EDIT:
It DOES trigger Super Class static initialization.
If the static field is final, and the static final field is initialized when declaring. Then it will neither load the class nor initialize the class, for this static final field is a compile time constant value. Attention: if the static final field is initialized in static block, then this statement does NOT hold anymore.
I think the point is that in a situation like this:
public class Superclass {
public static long INIT_TIME = System.currentTimeMillis();
static {
System.out.println("Initializing Superclass");
}
}
public class Subclass extends Superclass {
static {
System.out.println("Initializing Subclass");
}
}
This code:
long time = Subclass.INIT_TIME;
is actually compiled to:
long time = Superclass.INIT_TIME;
and only "Initializing Superclass" will be printed, even though the source code referred to Subclass.
An example:
class A {
public static int nA = 0;
}
class B extends A {
public static int nB = 1;
}
class C extends B {
public static int nC = 2;
}
Client:
int test = B.nA;
The JVM will initialize only Class A. Not B nor C.
As shown above, when I run the Superclass/Subclass example, on calling Subclass.INIT_TIME,
both the Superclass and Subclass static initializers are getting invoked.
But here it is said that only "Initializing Superclass" will be printed.
Can someone clarify?

Categories