问题描述:

public class Test{

static Test test = new Test();

static {

System.out.println("Test class ...");

}

public static void main(String[] args){

}

}

See code above , class Test will get loaded when main is called and a static instance called test will be constructed , has Test class been loaded already when static Test test = new Test(); is called ? If not , is it safe to do like this ? If loaded, is it safe to construct a new object when class has been loaded but not initialized ?

Edit

Code above seems to be causing much concern about the main method while it is not what I am asking .

public class App{

public static void main(String[] args) {

new Test();

}

}

class Test{

static Test app = new Test();

static{

System.out.println("Test ");

}

{

System.out.println("constructing a Test object ...");

}

}

Code here , am I constructing Test object before Test class initialized ? Is it safe to do so ? Is @Thirler's answer telling that it is not safe but can do so ?

网友答案:

This is allowed, and most of the time this will go fine. However this will allow you to create some constructs which seem fine at a quick glance, but fail. For instance the circular reference below.

public class InitTest {
    static InitTest test = new InitTest();

    private int count = 0;

    public static void main(String[] args) {

    }

    public InitTest() {
        test.count++;
    }
}

Here the constructor of the static object calls itself. Since the constructor has not yet finished, the object has not yet been assigned (only finished objects are assigned). And this will cause a NullPointerException on test.count++;

Note that the Java Language Specification is quiet readable, chapter 12 talks about loading classes and specifies the order of initialization (which is the formal name of the phase we are talking about, which gets all static variables initialized). Sections 12.4.1 talks about this some more (though rather vaguely). The bold part (my emphasis) refers to the example above and your question.

The intent is that a class or interface type has a set of initializers that put it in a consistent state, and that this state is the first state that is observed by other classes. The static initializers and class variable initializers are executed in textual order, and may not refer to class variables declared in the class whose declarations appear textually after the use, even though these class variables are in scope (§8.3.3). This restriction is designed to detect, at compile time, most circular or otherwise malformed initializations.

The fact that initialization code is unrestricted allows examples to be constructed where the value of a class variable can be observed when it still has its initial default value, before its initializing expression is evaluated, but such examples are rare in practice. (Such examples can be also constructed for instance variable initialization (§12.5).) The full power of the Java programming language is available in these initializers; programmers must exercise some care. This power places an extra burden on code generators, but this burden would arise in any case because the Java programming language is concurrent (§12.4.2).

Basically they say: because we want initialization to be strong and not place many restrictions, it is possible, but rare to create situations that wont work.

相关阅读:
Top