문제

Considering the code below, it runs without throw any exception.

public class Test1 {
    public static int k = 0;
    public static Test1 t1 = new Test1("t1");
    public static Test1 t2 = new Test1("t2");
    public static int i = print("i");
    public static int n = 99;
    public int j = print("j");
    {
        print("constructor block");
    }

    static {
        print("static block");
    }

    public Test1(String str) {
        System.out.println((++k) + ":" + str + "    i=" + i + "    n=" + n);
        ++i;
        ++n;
    }

    public static int print(String str) {
        System.out.println((++k) + ":" + str + "    i=" + i + "    n=" + n);
        ++n;
        return ++i;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Test1 t = new Test1("init");
    }

}

output :

1:j    i=0    n=0
2:constructor block    i=1    n=1
3:t1    i=2    n=2
4:j    i=3    n=3
5:constructor block    i=4    n=4
6:t2    i=5    n=5
7:i    i=6    n=6
8:static block    i=7    n=99
9:j    i=8    n=100
10:constructor block    i=9    n=101
11:init    i=10    n=102

I step through it with a debugger. can see the clinit method calls init method. Since the clinit method is still a part of class loading, does this mean we can instantiate Test1 object before the Test1 class is well prepared?

도움이 되었습니까?

해결책

I'd have to look up the exact definition in the spec (you can do that as well) but let's put it that way:

Suppose you have the following:

class A {
  static B b = new B();
}

class B {
   static A a = new A(); 
}

If the classes would have to be fully initialized before creating new instances, i.e. all static initializers would have to run, you'd have a deadlock. Not allowing to create new instances in a static block would severely limit the language and thus there must be some way to resolve this.

As I said, I'd have to look this up but AFAIK the default order is like this:

  • classes are loaded and static variables are initialized to their defaults
  • as constructors are called top-down (i.e. from super class to sub class)
    • first the static initializer blocks (i.e. initializing static variables as well as static blocks) are called in order of definition
    • then the instance initializer block for the current class is executed and
    • last the constructor is executed

Of course there are ways to mess with that order as you already found out but that's generally not recommended since you could end up with undefined/messy behavior. One such case would be calling a method in the super class constructor which is being overridden in the subclass and which accesses (not yet initialized) fields of the subclass.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top