在Java中,main方法后的语句初始化顺序是什么?

9

我了解到初始化顺序的原则是:

  1. 首先是父类(在这种情况下不讨论)
  2. 按照出现的顺序进行静态变量声明和静态初始化块
  3. 按照出现的顺序进行实例变量声明和静态初始化块
  4. 构造函数

但是我仍然对以下代码的输出感到困惑:

public class Test1 {

    static {
        add(2);
    }

    static void add (int num) {
        System.out.println(num + " ");
    }

    public Test1() {
        add(5);
        System.out.println("Constructor!");
    }

    static {
        add(4);
    }

    {
        add(6);
    }

    static {
        new Test1();
    }

    {
        add(8);
    }

    public static void main(String[] args) {
        System.out.println("Main method!");
        add(10);
    }

    {
        add(11);
    }
    static {
        add(12);
    }
}

结果是:
2 
4 
6 
8 
11 
5 
Constructor!
12
Main method!
10 

如果没有add(10); add(11); add(12)的陈述,我完全可以理解。 请问您能否解释一下这3个语句的初始化顺序?

1
你正在类初始化期间调用构造函数代码,这将强制执行非静态初始化块,但这并不意味着它会破坏静态初始化顺序。因此,你会看到 static 2 4;非静态(但从静态块中调用)6 8 11,构造函数 5;然后再次执行其余的静态块 12。现在当类完全初始化时,JVM 执行 main 方法 (10)。 - Pshemo
你忘记了常量的初始化,这个过程发生得非常早。为什么不阅读JLS关于初始化顺序的章节呢? - Lew Bloch
5个回答

7
静态初始化器是最先执行的,因此你会得到
2 
4

但在接下来的静态初始化程序中,您调用了Test1.class的新实例,因此触发了实例初始化程序,构造函数也在它们之后触发,从而得到:

6 
8 
11 
5 
Constructor!

然后调用其余的静态初始化器。所以:

12

最后是主方法:

Main method!
10 

7

1)像下面这样没有名称的块被称为 "实例初始化器",它只在创建新对象时被调用,就像默认构造函数或无参构造函数。

{
    add(11);
}

2) 在上述代码中,你使用了 静态块在类加载时首先调用),实例初始化器在创建对象时调用),显式默认构造函数在创建对象时调用,但请记住实例初始化器始终优先)以及最后的主方法。

3) 现在让我们分析一下你的代码:

第一个调用:

static 
{
   add(2); //print 2
}

第二次通话:

static {
        add(4); // print 4
}

第三次呼叫:

static {
    new Test1(); 
    // Here Object is getting created so all Instance Initialzer will be called first in a sequential manner.
}

第四次通话:
{
    add(6); // print 6
}

第五次通话:
{
    add(8);  // print 8
}

第六次呼叫:
{
    add(11);   // print 11
}

第七次调用:在实例初始化程序之后,将调用显式默认构造函数。

public Test1() {
    add(5);    // print 5
    System.out.println("Constructor!");   // print Constructor!
}
第8个调用: 再次调用最后一个静态块。
static {
    add(12);   // print 12
}

第九次调用:最终会调用主方法

public static void main(String[] args) {
    System.out.println("Main method!");  // print Main method!
    add(10); // print 10
}

1
在Java中,对于一个类,所有的静态初始化器按顺序执行(从类的顶部到底部),在所有构造函数之前执行。括号内的术语添加到构造函数中,这些不是静态初始化器(请参阅http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html)。
因此,Test1的实例1:
static {
    add(2);
}
...
static {
    add(4);
}

接下来,在静态块中有一个Test1的构造函数。它被调用,因此实例成员已经被初始化,因为之前的静态初始化程序已经被调用:

{
    add(6);
}
...
{
    add(8);
}
...
{
    add(11);
}

在构造函数中,接下来调用的是下一个操作:
add(5);

首先,我们返回到最后一个静态初始化器被调用的情况:

static {
    add(12);
}

最后,类已完全初始化,因此调用了主方法:

public static void main(String[] args) {
    System.out.println("Main method!");
    add(10);
}

所以,输出:

2 
4 
6 
8 
11 
5 
Constructor!
12
Main method!
10 

1

我觉得你感到困惑是因为(12)在(main method - 10)之前

这是因为主方法在最后被调用,但其他初始化顺序已经清晰了


1
无论@DontPanic回答的是否正确,我想强调的主要观点是源代码中代码块的顺序(从上到下)也很重要,你可以在Java文档这里查看。

一个类可以有任意数量的静态初始化块,并且它们可以出现在类体中的任何地方。运行时系统保证静态初始化块按照它们在源代码中出现的顺序被调用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接