在Java中使用大括号的奇怪行为

Eng*_*uad 40 java braces

当我运行以下代码时:

public class Test {

  Test(){
    System.out.println("1");
  }

  {
    System.out.println("2");
  }

  static {
    System.out.println("3");
  }

  public static void main(String args[]) {
    new Test();
  }
}
Run Code Online (Sandbox Code Playgroud)

我希望按此顺序获得输出:

1
2
3
Run Code Online (Sandbox Code Playgroud)

但我得到的是相反的顺序:

3
2
1
Run Code Online (Sandbox Code Playgroud)

任何人都可以解释为什么它以相反的顺序输出?

================

另外,当我创建多个实例时Test:

new Test();
new Test();
new Test();
new Test();
Run Code Online (Sandbox Code Playgroud)

静态块在第一次执行.

Ósc*_*pez 62

这一切都取决于初始化语句的执行顺序.您的测试表明此订单是:

  1. 静态初始化块
  2. 实例初始化块
  3. 构造函数

编辑

感谢您的评论,现在我可以引用JVM规范中的相应部分.是详细的初始化过程.

  • nitpick:测试*证明*没有.它确实*证明了你描述的顺序.要获得证明,您需要查看Java语言规范. (11认同)
  • double nitty pick - 我建议查看VM规范,而不是语言规范.具体而言,第2.17节.(注意,一些初始化程序以文本顺序执行). (6认同)
  • @ObscureRobot:无论你称之为"证明"还是"证明",它都是同一件事:一个经验事实.规范说应该发生什么,可能会或可能不会与什么/做/发生匹配.鉴于OP期望别的东西,任何一个词都是合适的(尽管我会认为这个证明有点好). (3认同)
  • 不,证明和示威是非常不同的.一般理论和个别经验证据.仅仅因为你今天在桌面上观察到某些行为并不意味着它明天会在那里.可能是您只是观察当前实现的一个怪癖,它将在您下次更新JDK或JRE时消失.差异很微妙但很重要."证明"在软件开发中几乎没有用...除非你和老板谈论新硬件的预算:) (3认同)

Der*_*est 31

3 - 是一个静态初始化程序,它在加载类时运行一次,这首先发生.

2 - 是初始化块,java编译器实际上会将其复制到每个构造函数中,因此如果您愿意,可以在构造函数之间共享一些初始化.很少用.

1 - 将在构造对象后执行,在(3)和(2)之后执行.

更多信息在这里


r0a*_*t3d 18

首先执行静态块.

然后是实例实例初始化块

请参阅JLS以获取实例化

{

// sop声明

}

你不能在实例初始化块中有一个返回语句,就像构造函数一样.


小智 5

Test(){System.out.println("1");}

    {System.out.println("2");}

    static{System.out.println("3");}
Run Code Online (Sandbox Code Playgroud)

静态事物首先被执行, {System.out.println("2");}不是函数的一部分,因为它的范围首先被调用,并且 Test(){System.out.println("1");}被称为last,因为其他两个被称为first


Dmi*_* B. 5

首先,将类加载到JVM中并进行类初始化.在此步骤中,执行静态块."{...}"只是"static {...}"的句法等价物.由于代码中已经存在"静态{...}"块,因此将附加"{...}".这就是为什么你在2之前打印3.

下一次加载类后,java.exe(我假设您从命令行执行)将找到并运行main方法.main静态方法初始化其构造函数被调用的实例,因此最后打印"1".