Java - 此代码中的初始化顺序是什么?

时间:2016-08-03 15:52:00

标签: java oop

在以下Java代码中,Insect类由Beetle类继承。

class Insect {

    private int i = 9;
    protected int j;

    Insect() {
        System.out.println("i = " + i + ", j = " + j);
        j = 39;
    }
    private static int x1
            = printInit("static Insect.x1 initialized");

    static int printInit(String s) {

        System.out.println(s);
        return 47;
    }
}

public class Beetle extends Insect {

    private int k = printInit("Beetle.k initialized");

    public Beetle() {
        System.out.println("k = " + k);
        System.out.println("j = " + j);
    }
    private static int x2
            = printInit("static Beetle.x2 initialized");

    public static void main(String[] args) {
        System.out.println("Beetle constructor");
        Beetle b = new Beetle();
    }
}

输出以某种方式令人着迷。

  

static Insect.x1已初始化

     

静态Beetle.x2初始化

     

甲壳虫构造函数

     

i = 9,j = 0

     

Beetle.k初始化

     

k = 47 j = 39

此特定示例中的初始化顺序是什么?

为什么在x1之后立即初始化x2?为什么主方法的第一行(System.out.println("Beetle constructor");)在 x1和x2 intializaton之后执行。好令人兴奋。

我知道派生类构造函数会自动调用基类构造函数(除非它有参数,你使用的是super关键字)。我知道变量在构造函数之前被初始化,静态变量在其他变量之前被初始化。

3 个答案:

答案 0 :(得分:4)

x1x2是静态的。这意味着它们在加载类时被初始化。由于main方法位于Beetle,因此必须在调用main之前加载该类。这就是为什么x1x2初始化是您看到的第一件事。不确定为什么这两个的顺序是这样的。

现在您正在调用main并执行System.out.println("Beetle constructor");。然后它调用Beetle(),它首先隐式调用super()(又名Insect())。这会打印i = 9, j = 0,因为i为9且j尚未在该点初始化,这意味着它具有默认的int值0。

现在j设置为39,流程在Beetle()继续。现在,这会根据您的Beetle初始化k字段。因此,当涉及到Beetle()中的显式代码时,超级构造函数会将k初始化为47并将j初始化为39。

答案 1 :(得分:2)

这可以解释如下 -

由于静态成员是非实例成员,即在该类的所有实例中只共享该成员的一个副本,因此首先初始化这些成员。

在这种情况下,首先初始化x1,因为它的静态成员存在于main方法所在类的基类中。

因此,第一个x1被初始化

子类中的静态成员x2是由于相同的原因,也是因为昆虫类中没有其他静态成员。

从主方法打印甲壳虫构造函数。

出于显而易见的原因,一个接一个地调用超类和子类的构造函数

答案 2 :(得分:2)

JVM(类加载器)在调用其主静态方法时加载Beetle类。在类加载之后,将发生Beetle类的初始化,这意味着初始化类的所有静态成员。

基类始终是隐式初始化的,因此您可以看到在x2之前初始化的x1。

你会看到" Beetle构造函数"在x1和x2之后打印,因为当你引用类的静态方法时(正如你通过调用main那样),JVM执行顺序跳转到初始化类静态成员,然后继续执行main()方法

作为实验,请尝试将main方法移除到另一个类

public class Beetle1 {
 public static void main(String[] args) {
        System.out.println("Beetle1 constructor");
    }
}

现在由于未引用Beetle构造函数,类加载器不会加载它,您将看到打印Beetle1构造函数。