JVM执行代码以构建对象的顺序

时间:2019-05-20 14:14:00

标签: java

我正在研究Oracle的OCA 8认证。在我的研究中,我遇到了一个问题,这个问题使我对Java对象的初始化顺序(静态块,构造函数,变量的初始化等等)产生了一些疑问。问题如下:

public class InitTest{
   static String s1 = sM1("a");{
      s1 = sM1("b");
   }
   static{
      s1 = sM1("c");
   }
   public static void main(String args[]){
      InitTest it = new InitTest();
   }
   private static String sM1(String s){
      System.out.println(s);  return s;
   }
}

我的问题是对象各部分的启动顺序:

1) {...}

2)静态{...}

3) InitTest {...}

4)静态字符串s1 = sM1(“ a”);

能给我解释一下吗?

3 个答案:

答案 0 :(得分:2)

首先:s1 = sM1("b")的一部分的格式与s1定义的一部分一样,但是完全独立。

static { ... }static String s1 =sM1("a")都是静态的,这意味着它们在JVM加载类时运行,并且在Main中的任何代码之前运行。它们按照写入的顺序执行。

{...}InitTest{...}不是静态的,它们仅在您创建InitTest的实例时运行。
{...}initialization block,在构造函数之前运行。

答案 1 :(得分:2)

首先要解决所有静态问题,因为没有理由保证对象的可用性,一个类中可能的静态内容是, a)静态实例变量 b)静态代码块 c)静态方法 和以相同顺序求值(尽管静态方法的顺序无关紧要)。因此,在您的情况下,首先评估s1 = SM1(“ a”),从而导致调用sM1(“ a”)方法。接下来,执行静态代码块,生成sM1(“ c”),最后使用sM1(“ b”)执行实例代码块。如果您碰巧在此类中没有arg构造函数,那么它将在对象可用之前作为最后一步被调用。

答案 2 :(得分:2)

初始化顺序始终如下

  1. 以递归方式初始化超类(与所涉及的示例无关,因为它没有超类)
  2. 静态字段和静态初始化程序
  3. 实例字段和实例初始化程序
  4. 构造函数

因此,示例中的初始化顺序为:

1)静态字符串s1 = sM1(“ a”); -首先要处理静态初始化块和静态字段成员,这是在类加载器加载类之后(在开始使用clas1s或创建对象之前)发生的。如果有更多的初始化程序或静态成员声明,​​则将按其写入顺序执行它们。这就是为什么此静态字段将在静态初始化程序块之前被初始化的原因。

2)静态{...} -在第1点中进行了说明。静态初始化器位于静态变量 s1 的声明之前,因此这是在静态变量中对其进行处理的原因。此顺序(两者具有相同的优先级,但如果两者具有相同的prio,则在班级内部的顺序将获胜)。

3) {...} -在静态初始值设定项和静态字段之后,实例初始值设定项和实例字段被初始化,因此实例初始值设定项在静态初始值设定项和静态字段 s1 。使用构造函数创建新对象时,它们是第一个被处理的,并且发生在构造函数实际执行之前。

4。) InitTest {...} -在初始化所有其他内容(所有初始化块和字段初始化)之后,调用构造函数。

有关类和对象初始化顺序的更多详细信息,您可以在Java语言规范中找到:https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4.1https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.4.2https://docs.oracle.com/javase/specs/jls/se11/html/jls-12.html#jls-12.5