java在初始化过程_Java初始化过程
這篇文章主要講解Java在創(chuàng)建對象的時候,初始化的順序。主要從以下幾個例子中講解:
繼承關(guān)系中初始化順序
初始化塊與構(gòu)造器的順序
已經(jīng)加載過的類的初始化順序
加載父類,會不會加載子類
創(chuàng)建子類對象會不會創(chuàng)建父類對象
例子1——繼承關(guā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é)果,我們可以知道在有繼承的時候,雖然是創(chuàng)建一個Son對象,但是JVM發(fā)現(xiàn)Son對象的類還沒有裝載,而Son類又繼承自Father類,只有加載了Father類,才能加載Son類。于是加載Father類的時候,就會初始化一切靜態(tài)變量和靜態(tài)塊。所以上文結(jié)果中第一行和第二行是父類靜態(tài)變量和靜態(tài)塊初始化的結(jié)果,然后加載完Father類之后,又會加載Son類,同樣是初始化Son類的靜態(tài)塊和靜態(tài)變量,出現(xiàn)上文中第三行和第四行的結(jié)果。等這個2個類都加載完了,才開始創(chuàng)建Son對象,因為Son對象,顯示調(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個語句塊叫初始化塊。在上文的結(jié)果中是初始化塊的執(zhí)行是先于構(gòu)造器的,現(xiàn)在看一下把初始化塊的內(nèi)容放到構(gòu)造器下面,會是什么的結(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í)行......
很顯然,無論初始化塊寫在哪個地方,都是先于構(gòu)造器執(zhí)行的,但是初始化塊之間的順序是前面的先初始化,后面在初始化。
例子3——已經(jīng)加載過的類的初始化順序
更改一下例子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)建父類對象的時候,加載Father類,出現(xiàn)第一行和第二行的結(jié)果,但是這個竟然會還把子類的靜態(tài)變量和靜態(tài)塊初始化?這個原因,例子4在說。 最后執(zhí)行父類的構(gòu)造器創(chuàng)建父類對象。當再創(chuàng)建子類的時候,發(fā)現(xiàn)父類和子類已經(jīng)加載過了,所以不會再加載Father和Son類,只會調(diào)用父類的構(gòu)造器,再執(zhí)行后續(xù)子類構(gòu)造器的內(nèi)容,創(chuàng)建子類。
例子4——加載父類,會不會加載子類
用一個嶄新的例子來看看上面,創(chuàng)建父類的時候,為什么會打印出子類靜態(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)初始化塊
這次就不會創(chuàng)建父類的時候,加載子類。例子3之所以出現(xiàn)這個原因 是因為main函數(shù)在子類中寫的,要執(zhí)行main函數(shù)必須要加載子類。只會加載子類之前要先加載父類,因為不加載父類,只加載子類,怎么讓子類調(diào)用父類的方法和變量。但是加載父類不會加載子類,反正父類也調(diào)用不了子類的方法。
例子5——創(chuàng)建子類對象會不會創(chuàng)建父類對象
做個實驗,看一下創(chuàng)建子類對象的時候,到底會不會創(chuàng)建一個父類對象,先說結(jié)論:不會。從道理上講,如果創(chuàng)建任何一個對象都要創(chuàng)建出一個他的父類對象的話,那么整個JVM虛擬機都是Object對象。看下面的實驗:
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
可以看出來,創(chuàng)建子類對象時那個父類的Class還是子類的,也就是說創(chuàng)建子類對象并沒有創(chuàng)建一個父類的對象,只是說調(diào)用了父類的構(gòu)造器,對父類的屬性進行初始化,并且給子類提供了一個super指示器去調(diào)用父類中那些變量和方法。
更詳細的說,new一個對象實際上是通過一個new指令開辟一個空間,來存放對象。在new ObjectSon()的時候,就只有一個new指令,只會開辟一個空間,所謂初始化父類等等,都是在這個空間中有一個特殊的區(qū)域來存放這些數(shù)據(jù),而super關(guān)鍵字就是提供了訪問這個特殊區(qū)域的方法,通過super去訪問這個特殊區(qū)域。
還可以比較super和this的hashcode來判斷,結(jié)果必然是兩者的hashcode是一致的。
總結(jié)
至此,Java初始化的講解到結(jié)束了,基本了覆蓋了絕大多數(shù)情況中的初始化。
總結(jié)
以上是生活随笔為你收集整理的java在初始化过程_Java初始化过程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java coding_java cod
- 下一篇: es java match_ES mul