java在初始化过程_Java初始化过程
這篇文章主要講解Java在創(chuàng)建對(duì)象的時(shí)候,初始化的順序。主要從以下幾個(gè)例子中講解:
繼承關(guān)系中初始化順序
初始化塊與構(gòu)造器的順序
已經(jīng)加載過(guò)的類的初始化順序
加載父類,會(huì)不會(huì)加載子類
創(chuàng)建子類對(duì)象會(huì)不會(huì)創(chuàng)建父類對(duì)象
例子1——繼承關(guān)系中初始化順序
先看簡(jiǎn)單的情況,看下面的例子:
public class Father {
public String fatherVar = "父類構(gòu)造塊初始化";
public static int fatherStaticVar;
public int i;
static {
int i = 100;
System.out.println("父類靜態(tài)塊初始化,i的值為" + i);
System.out.println("父類靜態(tài)變量初始化,fatherStaticVar的值為" + fatherStaticVar);
}
{
System.out.println(fatherVar);
}
public Father(){
System.out.println("父類構(gòu)造函數(shù)的初始化,i的值" + i);
}
}
public class Son extends Father {
public String sonVar = "子類構(gòu)造塊初始化";
public static int sonStaticVar;
public int i;
static {
int i = 101;
System.out.println("子類靜態(tài)塊初始化,i的值為" + i);
System.out.println("子類靜態(tài)變量初始化,sonStaticVar的值為" + sonStaticVar);
}
{
System.out.println(sonVar);
}
public Son(){
super();
System.out.println("子類構(gòu)造函數(shù)的初始化,i的值" + i);
}
public static void main(String[] args) {
new Son();
}
}
其執(zhí)行的結(jié)果如下:
父類靜態(tài)塊初始化,i的值為100
父類靜態(tài)變量初始化,fatherStaticVar的值為0
子類靜態(tài)塊初始化,i的值為101
子類靜態(tài)變量初始化,sonStaticVar的值為0
父類構(gòu)造塊初始化
父類構(gòu)造函數(shù)的初始化,i的值0
子類構(gòu)造塊初始化
子類構(gòu)造函數(shù)的初始化,i的值0
按照結(jié)果,我們可以知道在有繼承的時(shí)候,雖然是創(chuàng)建一個(gè)Son對(duì)象,但是JVM發(fā)現(xiàn)Son對(duì)象的類還沒(méi)有裝載,而Son類又繼承自Father類,只有加載了Father類,才能加載Son類。于是加載Father類的時(shí)候,就會(huì)初始化一切靜態(tài)變量和靜態(tài)塊。所以上文結(jié)果中第一行和第二行是父類靜態(tài)變量和靜態(tài)塊初始化的結(jié)果,然后加載完Father類之后,又會(huì)加載Son類,同樣是初始化Son類的靜態(tài)塊和靜態(tài)變量,出現(xiàn)上文中第三行和第四行的結(jié)果。等這個(gè)2個(gè)類都加載完了,才開始創(chuàng)建Son對(duì)象,因?yàn)镾on對(duì)象,顯示調(diào)用了Father類的構(gòu)造器,所以先執(zhí)行Father類的構(gòu)造器,出現(xiàn)第五行和第六行的結(jié)果,等Father類構(gòu)造器執(zhí)行完了,才執(zhí)行后續(xù)Son構(gòu)造器的內(nèi)容,所以最后出現(xiàn)了第七行和第八行的結(jié)果。
例子2——初始化塊與構(gòu)造器的順序
在上面的例子中,有2個(gè)語(yǔ)句塊叫初始化塊。在上文的結(jié)果中是初始化塊的執(zhí)行是先于構(gòu)造器的,現(xiàn)在看一下把初始化塊的內(nèi)容放到構(gòu)造器下面,會(huì)是什么的結(jié)果
public class InitBlock {
public InitBlock(){
System.out.println("構(gòu)造器在執(zhí)行......");
}
{
System.out.println("初始化塊1在執(zhí)行......");
}
{
System.out.println("初始化塊2在執(zhí)行......");
}
public static void main(String[] args) {
new InitBlock();
}
}
結(jié)果如下:
初始化塊1在執(zhí)行......
初始化塊2在執(zhí)行......
構(gòu)造器在執(zhí)行......
很顯然,無(wú)論初始化塊寫在哪個(gè)地方,都是先于構(gòu)造器執(zhí)行的,但是初始化塊之間的順序是前面的先初始化,后面在初始化。
例子3——已經(jīng)加載過(guò)的類的初始化順序
更改一下例子1中的main方法,改成如下:
public static void main(String[] args) {
new Father();
System.out.println("=============");
new Son();
}
結(jié)果如下:
父類靜態(tài)塊初始化,i的值為100
父類靜態(tài)變量初始化,fatherStaticVar的值為0
子類靜態(tài)塊初始化,i的值為101
子類靜態(tài)變量初始化,sonStaticVar的值為0
父類構(gòu)造塊初始化
父類構(gòu)造函數(shù)的初始化,i的值0
=============
父類構(gòu)造塊初始化
父類構(gòu)造函數(shù)的初始化,i的值0
子類構(gòu)造塊初始化
子類構(gòu)造函數(shù)的初始化,i的值0
結(jié)果很有意思,創(chuàng)建父類對(duì)象的時(shí)候,加載Father類,出現(xiàn)第一行和第二行的結(jié)果,但是這個(gè)竟然會(huì)還把子類的靜態(tài)變量和靜態(tài)塊初始化?這個(gè)原因,例子4在說(shuō)。 最后執(zhí)行父類的構(gòu)造器創(chuàng)建父類對(duì)象。當(dāng)再創(chuàng)建子類的時(shí)候,發(fā)現(xiàn)父類和子類已經(jīng)加載過(guò)了,所以不會(huì)再加載Father和Son類,只會(huì)調(diào)用父類的構(gòu)造器,再執(zhí)行后續(xù)子類構(gòu)造器的內(nèi)容,創(chuàng)建子類。
例子4——加載父類,會(huì)不會(huì)加載子類
用一個(gè)嶄新的例子來(lái)看看上面,創(chuàng)建父類的時(shí)候,為什么會(huì)打印出子類靜態(tài)初始化執(zhí)行的結(jié)果。
public class StaticFather {
static{
System.out.println("父類靜態(tài)初始化塊");
}
}
public class StaticSon extends StaticFather{
static {
System.out.println("子類靜態(tài)初始化塊");
}
}
public class Test {
public static void main(String[] args) {
new StaticFather();
}
}
結(jié)果如下:
父類靜態(tài)初始化塊
這次就不會(huì)創(chuàng)建父類的時(shí)候,加載子類。例子3之所以出現(xiàn)這個(gè)原因 是因?yàn)閙ain函數(shù)在子類中寫的,要執(zhí)行main函數(shù)必須要加載子類。只會(huì)加載子類之前要先加載父類,因?yàn)椴患虞d父類,只加載子類,怎么讓子類調(diào)用父類的方法和變量。但是加載父類不會(huì)加載子類,反正父類也調(diào)用不了子類的方法。
例子5——?jiǎng)?chuàng)建子類對(duì)象會(huì)不會(huì)創(chuàng)建父類對(duì)象
做個(gè)實(shí)驗(yàn),看一下創(chuàng)建子類對(duì)象的時(shí)候,到底會(huì)不會(huì)創(chuàng)建一個(gè)父類對(duì)象,先說(shuō)結(jié)論:不會(huì)。從道理上講,如果創(chuàng)建任何一個(gè)對(duì)象都要?jiǎng)?chuàng)建出一個(gè)他的父類對(duì)象的話,那么整個(gè)JVM虛擬機(jī)都是Object對(duì)象??聪旅娴膶?shí)驗(yàn):
public class ObjectFather {
public void getInfo(){
System.out.println(getClass().toString());
}
}
public class ObjectSon extends ObjectFather{
public ObjectSon(){
super();
super.getInfo();
}
public static void main(String[] args) {
new ObjectSon();
}
}
結(jié)果如下:
class com.byhieg.init.ObjectSon
可以看出來(lái),創(chuàng)建子類對(duì)象時(shí)那個(gè)父類的Class還是子類的,也就是說(shuō)創(chuàng)建子類對(duì)象并沒(méi)有創(chuàng)建一個(gè)父類的對(duì)象,只是說(shuō)調(diào)用了父類的構(gòu)造器,對(duì)父類的屬性進(jìn)行初始化,并且給子類提供了一個(gè)super指示器去調(diào)用父類中那些變量和方法。
更詳細(xì)的說(shuō),new一個(gè)對(duì)象實(shí)際上是通過(guò)一個(gè)new指令開辟一個(gè)空間,來(lái)存放對(duì)象。在new ObjectSon()的時(shí)候,就只有一個(gè)new指令,只會(huì)開辟一個(gè)空間,所謂初始化父類等等,都是在這個(gè)空間中有一個(gè)特殊的區(qū)域來(lái)存放這些數(shù)據(jù),而super關(guān)鍵字就是提供了訪問(wèn)這個(gè)特殊區(qū)域的方法,通過(guò)super去訪問(wèn)這個(gè)特殊區(qū)域。
還可以比較super和this的hashcode來(lái)判斷,結(jié)果必然是兩者的hashcode是一致的。
總結(jié)
至此,Java初始化的講解到結(jié)束了,基本了覆蓋了絕大多數(shù)情況中的初始化。
總結(jié)
以上是生活随笔為你收集整理的java在初始化过程_Java初始化过程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: java coding_java cod
- 下一篇: java美元兑换,(Java实现) 美元