I have 2 classes:
Class A:
public class A {
static B b = new B();
static {
System.out.println("A static block");
}
public A() {
System.out.println("A constructor");
}
}
Class B:
public class B {
static {
System.out.println("B static block");
new A();
}
public B() {
System.out.println("B constructor");
}
}
I create a Main class which just creates new A:
public class Main {
public static void main(String[] args) {
new A();
}
}
The output I get is:
B static block
A constructor
B constructor
A static block
A constructor
As you can see, the constructor of A is invoked before its static initializer.
I understand it got something to do with the cyclic dependency I created but I was under the impression the static initializer should always run before the constructor.
What is the reason for this to happen (technically in the java implementation) ?
Is it recommended to avoid static initializers all together ?
static B b = new B();
is before
static {
System.out.println("A static block");
}
So you require that the B instance be initialized before you print "A static block".
And initializing the B class means you need to create a A instance. So there's no way for "A static block" to be printed before the A instance is constructed.
Yes, the static initialization of A is launched before the constructor is launched but, apart deadlocking, there would be no other solution to the sequence you require.
Note the warning in the specification :
Because the Java programming language is multithreaded, initialization
of a class or interface requires careful synchronization, since some
other thread may be trying to initialize the same class or interface
at the same time. There is also the possibility that initialization of
a class or interface may be requested recursively as part of the
initialization of that class or interface; for example, a variable
initializer in class A might invoke a method of an unrelated class B,
which might in turn invoke a method of class A. The implementation of
the Java virtual machine is responsible for taking care of
synchronization and recursive initialization by using the following
procedure [the doc goes on with the complete procedure]
A best practice, in Java as in other languages, is basically to avoid cyclic dependencies as their resolution may be very hard to predict.
Related
What does it mean when we say a class is "loaded"?
For example it is said that Static init blocks are executed at the time of class loading. When exactly class is loaded?
Please see this code from Kathy Sierra's book:
class Bird {
{
System.out.print("b1 ");
}
public Bird() {
System.out.print("b2 ");
}
}
class Raptor extends Bird {
static {
System.out.print("r1 ");
}
public Raptor() {
System.out.print("r2 ");
}
{
System.out.print("r3 ");
}
static {
System.out.print("r4 ");
}
}
class Hawk extends Raptor {
public static void main(String[] args) {
System.out.print("pre "); //1
new Hawk();//2
System.out.println("hawk ");
}
}
The output of above code is: r1 r4 pre b1 b2 r3 r2 hawk
I cant not understand howcome pre is printed after r1. Which part of the code loaded Raptor class?
One of the answer says :
"the class is initialized at the last possible moment, but before any of its members is accessed".
But by that logic, shouldn't pre be printed BEFORE r1? Since line 2 accesses constructor of class Raptor AFTER execution of line1.
Don't confuse class loading, which is implementation-specific, and class initialization, which is very strictly specified. Unfortunately these two terms are often used as if they meant the same thing, but usually the phrase "the time of class loading" refers to the time of class initialization.
As an executive summary of the detailed case-by-case rules, the class is initialized at the last possible moment, but before any of its members is accessed.
With that part cleared up, in the code of your example you have a class Hawk extends Raptor extends Bird. Hawk is the class containing the entry point of your program, the method main. This is the init order:
Start initializing Hawk. Is its parent class Raptor initialized? no.
Start initializing Raptor. Is its parent Bird initialized? no.
Start initializing Bird.
Complete initializing Bird.
Execute Raptor's static init blocks. This prints r1 r4.
Complete initializing Raptor.
Complete initializing Hawk.
Start executing Hawk.main(). This prints pre.
Usually when you first attempt to use the class, e.g. try to create an instance, use one of its static methods or store reference to the class' Class<?> object.
Note that this may depend on the classloader implementation.
Different JVMs load classes in different ways, but the basic rule is only loading classes when they are needed. If there are some other classes that are required by the loaded class, they will also be loaded. The loading process is recursive.
Below code is simple example of class and static block,variable laoding.
public class Foo {
//instance variable initializer
String s = "abc";
//constructor
public Foo() {
System.out.println("constructor called");
}
//static initializer
static {
System.out.println("static initializer called");
}
//instance initializer
{
System.out.println("instance initializer called");
}
public static void main(String[] args) {
new Foo();
new Foo();
}
}
Output for above program :
static initializer called
instance initializer called
constructor called
instance initializer called
constructor called
public class sup {
static {
System.out.print("In Sup ");
}
}
public class sub extends sup {
static {
System.out.print("In Sub");
}
}
final public class test extends sub {
static int a = 10;
static {
System.out.print(" In test" + a);
}
{
System.out.print(" In test" + a);
}
public static void main(String[] args) {
}
}
Output:
In Sup In Sub In test10
But here I am not creating object. The JVM should call the main method which is static and initialize the main class only. So it should give output In test10.
Could anyone please explain why I'm getting different output?
static initializer blocks are called when the class loader loads a class. In a nutshell, the order of execution here is as follows:
Attempt to load test, see it depends on sub
Attempt to load sub, see it depends on sup
Attempt to load sup
sup is loaded, and its static block prints "In Sup"
sub's loading is resumed, and its static block prints "In Sub"
test's loading is resumed, and a is initialized to 10.
test's static block is executed and prints " In test10"
test's main function is executed, and does nothing, since it's empty.
Static blocks are executed before main method. Since test extends sub and sub extends sup, the static block of sup will be executed, then the static block of sub and finally the static block of test.
See the JLS - 12.4.1. When Initialization Occurs for detailed explanation:
class Super {
static { System.out.print("Super "); }
}
class One {
static { System.out.print("One "); }
}
class Two extends Super {
static { System.out.print("Two "); }
}
class Test {
public static void main(String[] args) {
One o = null;
Two t = new Two();
System.out.println((Object)o == (Object)t);
}
}
This example demonstrates the order of execution, the output would be
Super Two false
here i am not creating object.. It is not about creation of objects. Even before you create an object, the class and its related dependencies have to be loaded / initialized. Classes can get loaded when you access static methods present in them (main is static). Since your test class depends on sub and sub depends on sup, the JVM loads them in the order sup --> sub --> test so that the dependencies for the class 'test' are resolved. Unless this is done, your 'test' cannot use fields / methods of its super classes.
static block/variable/methods are not inheritable as they belong to class not object.
The reason why you are getting this output is, JVM needs to load the main class's complete hierarchy to execute the main method (parent class then child).
If you remove the inheritance from test class, you would get only 'In test10'.
The JVM will load a class when the class is run regardless of whether you create an instance of the class or not.
This is clearly specified in Section 12.1.1 of the Java language specification.
java Test reboot Bob Dot Enzo
The initial attempt to execute the method main of class Test discovers that the class Test is not loaded - that is, that the Java Virtual Machine does not currently contain a binary representation for this class. The Java Virtual Machine then uses a class loader to attempt to find such a binary representation
class A {
static int super_var = 1;
static {
System.out.println("super");
}
}
class B extends A {
static int sub_var = 2;
static {
System.out.println("sub");
}
}
public class Demo{
public static void main(String []args){
System.out.println(B.super_var);
}
}
outputs are :
super
1
this means that the child class not going to load or any other thing? how is it works?
When you access the static fields of a super class on subclass reference, only the class that declares the field will be loaded and initialized, in this case it is A. This is specified in JLS §12.4.1 - When Initialization Occurs:
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.
Emphasis mine.
So in your code, class B would not even be initialized, and hence its static block would not be executed.
Checkout the answer to this question: In what order do static initializer blocks in Java run?
The static block gets called only when a class is accessed (either creating an instance or accessing a member field or static method). However, you access a member of class A only, so there is no reason for class B to be initialized yet. The static initializer of B will be called as soon as you access a member from that class (either a field or static method, or create an instance from class B).
The reason is that class B doesn't need to be initialized until you access one of its members. Because A doesn't know about B (and cannot access it) there's really no reason for B to initialize at that stage.
You will find out that when you access B.sub_var the static initializer of B will be executed.
This is a bit of a tricky one to explain, but let's say I have two classes A and B. A contains a static list of factory objects that are registered by each object that provides such a factor. In this example B is such a class and provides an imaginary Factory implementation.
Class A:
public class A {
protected static Map<String, Factory> registered = new HashMap<String, Factory>();
protected static register(String name, Factory factory) {
registered.put(name, factory);
}
public A() {
// Do something with the factories we've registered
}
}
Class B:
public class B {
static {
A.register("Foo", new Factory() {
public Object create() {
return new B();
}
});
}
public B() {
// Create a new instance of class B
}
}
In my program for some strange reason the static block within B is never called, so when I start interacting with A no factories have been registered so it can't do what it needs to do.
If I move the creation of each Factory into A directly there is no problem of course. I'm working under the assumption that because there are no clear references to B from any class that the compiler isn't recognising there's a link between A and B so doesn't bother with B at all. Is there anything I can do to work around this? I'd hoped to avoid adding each new factory into A directly as it makes maintenance more difficult than having new factories simply register themselves, but clearly having none of them work at all is even worse; still, I'd like to somehow get it to work as intended if I can.
In case it's relevant, the particular JVM I'm working with is the Android JVM, could this be a side-effect of some optimisation that that that JVM is using?
You can read about class loading in this blog post. The point is that a class won't be loaded until it is referenced. And the static blocks of a class won't be executed until the class is loaded. The rules are
an Instance of class is created using either new() keyword or using reflection using class.forName(), which may throw ClassNotFoundException in Java.
an static method of Class is invoked.
an static field of Class is assigned.
an static field of class is used which is not a constant variable.
if Class is a top level class and an assert statement lexically nested within class is executed.
A solution is to either instantiate B or call a no-op static method (or any of the above).
public class B {
static {
A.register("Foo", new Factory() {
public Object create() {
return new B();
}
});
}
public void static noOp() {}
public B() {
// Create a new instance of class B
}
}
...
B.noOp();
The Oracle JVM spec states this here.
Simple java code snippet. It has three classes. After compiling the code please delete A.class and then execute the code. Code still runs, why its not checking whether the byte code of A exists or not?
class A {
static {
System.out.println("In the class A");
}
public A() {
}
}
class B {
private A a = null;
static {
System.out.println("In the class B");
}
public B() {
a = new A();
}
}
public class ExampleLinkage {
static {
System.out.println("In the class A");
}
public ExampleLinkage(String str) {
}
public static void main(String args[]) {
try {
System.out.println("In the main method of ExampleLinkage");
Class.forName("com.bt.rtti.B");
} catch(Exception e) {
e.printStackTrace();
}
}
}
I would guess that at no point the class A is needed to be loaded, even though there is an instance of it inside B, since you never instantiate an instance of B.
the JVM is very lazy when it load classes. it loads them either when you instantiate an object of that class (at the first time), when you explicitly load a class with Class.forName() or when you otherwise reference the class in a way that requires information from it (try accessing a static member of A from the static initializer of B and see that A will get loaded.
As your not recompiling it, just running the class.
Class A is not used in the code (i.e. in the main method).
At run-time classes are loaded as they are being used. At that time, you would get a ClassNotFoundError. But if you are not using the class, there is not need for it to be there.
Try to make an instance of B (which needs an instance of A), then you will get an error.
Further to Gordon's answer, you are only running the class, and class A is not required, if you called A's constructor or referenced a static field or method in A, then you would get the ClassNotFoundException you are expecting