-3

下面是一个程序,其中有两个静态块,在我看来应该在第一次通知时调用,但是按照从上到下的顺序,但这不会发生

public class StaticTest {  
    public static void main(String[] args) {  
        A a1 = new A();  
        A a2 = new A();  
        B b1 = new B();  
    }
}  

class A {  
    static {  
        System.out.println("Static block of Class A");  
    }  
    {  
        System.out.println("Non-Static block of a instance of Class A");  
    }  
    public A() {  
        System.out.println("Constructing object of type A");  
    }  
}  
class B {  
    static {  
        System.out.println("Static block of Class B");  
    }
    {  
        System.out.println("Non-Static block of a instance of Class B");  
    }
    public B() {  
        System.out.println("Constructing object of type A");  
    }  
}   
4

5 回答 5

3

究竟什么时候调用静态块或方法”——对于这样的问题,Java 语言规范为您提供了答案。

静态初始化器

类中声明的静态初始化器在类初始化时执行。与类变量的任何字段初始化器一起,静态初始化器可用于初始化类的类变量。

通过运行您的代码,您可以轻松找出首先运行的内容。

于 2013-07-04T13:01:18.323 回答
2

直到实际需要时class B才会执行静态块。B这仅在 main 方法的第 3 条语句中出现。实际上,如果您将该行替换为

if (2*2 == 5) new B();

你会注意到静态块B永远不会被执行,因为 B 甚至不会被加载。

要跟踪类加载,请使用-verbose:classjava 命令的选项。

于 2013-07-04T13:10:48.033 回答
1

静态块在各个类初始化时执行。

类初始化的顺序是由所涉及的类之间的静态和动态依赖组合决定的;请参阅静态类初始化何时发生?

然而,JLS 有效地提供了一组约束(这发生在此之前),通常有许多解决方案。这是一个例子,其中两个“解决方案”是可能的。

  1. 类在表达式构造A之前初始化new A()A

  2. 类在表达式构造B之前初始化new B()B

如您所见,A在之前BB之前初始化类A都是解决方案。

在这种情况下,没有指定初始化的实际顺序,并且很可能依赖于 JVM 和/或字节码编译器......并且不应依赖。

也可以构造一个场景,其中依赖存在循环,导致没有满足约束的顺序。在这种情况下,顺序也是不确定的,其中一个类可能会在未初始化状态下观察另一个类。(编译器或运行时都不会将此标记为错误!)这在 JLS 第8.3.2.3节中进行了描述。

幸运的是,这种情况很不寻常。


实例块和静态方法要简单得多:

  • 每次创建实例时,类的实例块都会按程序顺序执行。super(...)它们在构造函数的“调用”和该构造函数的下一行之间按顺序执行。(这同样适用于构造函数是默认构造函数和/或super()调用是隐式的。)

  • 静态方法在显式调用时执行。

于 2013-07-04T13:56:32.750 回答
1

这是您的测试的输出

Static block of Class A
Non-Static block of a instance of Class A
Constructing object of type A
Non-Static block of a instance of Class A
Constructing object of type A
Static block of Class B
Non-Static block of a instance of Class B
Constructing object of type A

我猜你很惊讶为什么Static block of Class A只打印一次。这是因为静态块只在类加载时运行一次。在你调用new A() JVM加载A.class之后,当你new A()再次调用时,不需要再次加载它

于 2013-07-04T13:04:54.527 回答
0

以下是您的程序的输出

Static block of Class A
Non-Static block of a instance of Class A
Constructing object of type A
Non-Static block of a instance of Class A
Constructing object of type A
Static block of Class B
Non-Static block of a instance of Class B
Constructing object of type A

首次创建类对象时,仅调用一次静态块

于 2013-07-04T13:14:14.363 回答