Java 为什么在类尚未完全加载时构造新对象是可以的?

Java 为什么在类尚未完全加载时构造新对象是可以的?,java,class,Java,Class,参见上面的代码,当调用main时,类Test将被加载,并且将构造一个名为Test的静态实例,当static Test Test=new Test()时,Test类已经被加载被调用了吗?如果不是,这样做安全吗?如果已加载,则在类已加载但未初始化时构造新对象是否安全 编辑 上面的代码似乎引起了人们对main方法的极大关注,而这并不是我要问的 public class Test{ static Test test = new Test(); static { Syste

参见上面的代码,当调用
main
时,类
Test
将被加载,并且将构造一个名为
Test
的静态实例,当
static Test Test=new Test()时,
Test
类已经被加载被调用了吗?如果不是,这样做安全吗?如果已加载,则在类已加载但未初始化时构造新对象是否安全

编辑
上面的代码似乎引起了人们对main方法的极大关注,而这并不是我要问的

public class Test{
    static Test test = new Test();
    static {
        System.out.println("Test class ...");
    }
    public static void main(String[] args){

    }
}

这里的代码,我是在初始化测试类之前构造测试对象的吗?这样做安全吗?@Thirler的回答是否表明它不安全,但可以这样做

这是允许的,而且大多数情况下都可以。然而,这将允许您创建一些结构,这些结构看起来很好,但很快就会失败。例如,下面的循环引用

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 ...");
    }
}
这里静态对象的构造函数调用自己。由于构造函数尚未完成,因此尚未分配对象(仅分配完成的对象)。这将导致
test.count++上出现
NullPointerException

请注意,Java语言规范是安静可读的,讨论了加载类并指定了初始化顺序(这是我们正在讨论的阶段的正式名称,它将初始化所有静态变量)。第12.4.1节对此进行了更多讨论(尽管相当模糊)。粗体部分(我的重点)指的是上面的例子和你的问题

目的是一个类或接口类型有一组初始值设定项 这使它处于一个一致的状态,并且这个状态是第一个 其他类观察到的状态。静态初始值设定项和 类变量初始值设定项是按文本顺序执行的,可能不会 引用其声明的类中声明的类变量 即使这些类变量是 在范围内(§8.3.3)。此限制旨在在编译时检测 时间,大多数循环或其他形式错误的初始化

初始化代码不受限制的事实允许示例 在可以观察到类变量值的地方构造 当它仍具有初始默认值时,在初始化之前 表达式是经过计算的,但这种示例在实践中很少出现。(例如 还可以构造实例变量初始化的示例 (§12.5)Java编程语言的全部功能可用 在这些初始化者中;程序员必须谨慎行事。这种力量 给代码生成器带来了额外的负担,但这种负担也会出现 无论如何,因为Java编程语言是并发的 (§12.4.2)


基本上,他们会说:因为我们希望初始化功能强大,并且没有太多限制,所以创建不起作用的情况是可能的,但很少发生。

它已经加载,如果不安全,编译器将禁止此类构造。@dunni在不初始化静态变量的情况下是否可以加载它?在调用main方法之前,将加载并初始化该类。有关详细信息,请参阅JLS当涉及到初始化静态变量时,您必须记住初始化的顺序。但这也是编译器要处理的事情。@horse\u带有\u no\u名称,我认为静态变量Test初始化时测试类没有初始化。看来我们确实可以在类完全初始化之前构造一个新对象吗?@你是对的,类的构造可以作为初始化的一部分来完成(这在单例模式中很常见)。但是,可以创建无法初始化的构造(这是我的示例)。
public class InitTest {
    static InitTest test = new InitTest();

    private int count = 0;

    public static void main(String[] args) {

    }

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