类的初始化顺序详解

前言

先声明一个常识,类域和局部变量初始化的差异如下,
局部变量不初始化会报错:
image_1clid1kt7fl1m5ma9b1bgo1c0g9.png-14.9kB

类中属性(也称域)不赋初值,默认为0,如果是引用默认为空。
image_1clid2vnjh9rec81urr1or1d69m.png-14.5kB


正题

一、类中属性按照定义的顺序初始化

我们声明一个Child类,拥有两个构造方法:
TIM截图20180823113529.png-16.2kB
我们在Main类中创建Child的两个对象:
TIM截图20180823113741.png-17.7kB
输出结果:
TIM截图20180823113844.png-9.4kB
结论:就算类中属性散乱定义在不同地方,初始化也会严格按照先后顺序执行。

二、属性的自初始化先于构造方法初始化

我们知道,构造方法的主要作用在于初始化类中的成员变量,那么它到底何时执行呢?
在这里,我们在构造函数里将child2引用指向了另一个对象:
TIM截图20180823121428.png-17.8kB
输出结果如下:
TIM截图20180823121407.png-1.9kB
我们看到,构造函数方法是后被调用的。
结论:构造函数的初始化晚于成员变量自初始化。

三、静态块和静态变量优先

静态方法又被称为类方法,静态属性被称为类域,总是最优先初始化。
静态方法初始化也有两种方法:

  1. 直接初始化
    image_1cligqpe41f177i17cp1n113fn51.png-24.3kB
    输出结果:
    image_1cligrem0gbv1rgq1gst10r4i9m5e.png-13.4kB

  2. 采用静态块统一初始化
    image_1clihbsskgq01os4ct61kvc19cs5r.png-28.7kB
    输出结果:
    image_1cligrem0gbv1rgq1gst10r4i9m5e.png-13.4kB

两种方法效果一样。但是,注意如果你静态块初始,你一定不能这么做:
image_1clihf7r8dec1r6bk06htpvc268.png-31.9kB
这样做你是访问不了静态属性的。
你可以这么理解:静态块其实相当于一个属于静态属性的初始化函数,你就算在里面定义了变量,作用周期也括号范围内。所以,你的正确做法是:在外面定义好静态类型的引用而统一在静态块中初始化。

结论:一个类中初始化顺序是:静态->类属性->构造函数。

四、继承关系中的初始化顺序

我们增加一个Parent类:
image_1clii4leg10tg1c51ob0npi1kbs75.png-18.1kB
然后让Child继承Paret类,并给Child增加一个静态块:
image_1cliih70r1bie19h11nkfbsk9mj8p.png-36.5kB
使用Main类调用Child:
image_1clii8lplusv6rs1maa1pu91ih57v.png-29.1kB
结果:
image_1cliiid2uc8a1vj01o9a1i3knho96.png-21.6kB

我们可以看到:Parent和Child的静态块先被调用,之后按照先父类后子类的顺序进行了初始化,而且静态属性只初始化一次
结论:拥有继承关系时,先是从父类到子类初始化静态属性,之后再是从父类到子类初始化非静态属性。


总结

  1. 单个类中初始化顺序:静态属性->非静态属性->构造函数
  2. 继承时初始化顺序:先从父类到子类初始化静态属性,再从父类到子类进行非静态初始工作。
  3. 静态属性都只初始化一次。
posted @ 2018-08-23 13:14  顾杰伟  阅读(558)  评论(0编辑  收藏  举报