標籤:java 類載入 初始化 建構函式
本人小白一枚,看java類的初始化的時候好暈的說,我覺著書上雖然說的對,但總覺得有些資訊沒說出來,沒說清楚,看了好多文章部落格的,現在有些感悟,來小寫下總結,也算是為以後再次複習種個好果子。
先摘一下書上寫的:
載入:將類的class檔案讀入記憶體,並為之建立一個java.lang.class對象。
串連:把類的位元據合并到JRE中,檢查被載入的類是否有正確的內部結構,並和其他類協調一致。為類的靜態FIELD分配記憶體,設定預設值,將類的位元據中的符號引用替換成直接引用。
初始化:主要對靜態Field進行初始化,初始化方式兩種:聲明靜態Field時指定的值,使用靜態初始化塊為其指定初始值。JVM會按他們的順序執行。初始化包括以下步驟:
假設該類沒有被載入和串連,則先載入並串連該類。
假設他的父類沒有被初始化,則先初始化他的父類
假設類中有初始化語句,則系統依次執行。
看完之後我腦子裡一直就盤旋著幾個問題:
1、類的載入和初始化神馬的和建構函式有啥關係和區別?
2、類的初始化會為執行個體屬性分配記憶體嗎?
3、如果我要建立一個執行個體對象,到底是怎麼個建立流程?
OK,如果你也有以上的疑問,那麼我們一起來看看到底是怎麼回事!我會直接回答最後一個問題,當你把這個問題弄明白了,前面的就迎刃而解了。
public class Person{
static{staticInt = 6; }
{vInt =15; }
static int staticInt = 3;
int vInt = 10;
Person(){
staticInt = 9;
vInt = 20;
}
}
Person p = new Person();
JVM會看:
1)哎,有個變數p,然後就給它分配一個空間(這裡的空間指的是指標,而不是實際的對象)
2)分完了以後發現它需要Person這個類來進行執行個體化,然後就到記憶體裡找,看這個類有沒有被載入到記憶體裡來,如果有救直接用了,如果沒有就會進行載入。我們就來說沒有的情況
3)載入的時候,將類的class檔案讀入記憶體,並為之建立一個java.lang.class對象。這裡需要重點說一下,在建立這個對象的時候,就會儲存這個類的所有資訊,比如這個類有哪些屬性(靜態非靜態都包括),有哪些方法(靜態非靜態都包括),有什麼代碼塊,都會被記錄。
4)把類的位元據合并到JRE中,檢查被載入的類是否有正確的內部結構,並和其他類協調一致。JVM跑到java.lang.class對象裡看看,都有啥靜態變數,為他們分配記憶體,設定預設值,將類的位元據中的符號引用替換成直接引用。
5)然後對靜態Field進行初始化,初始化方式兩種:聲明靜態Field時指定的值,使用靜態初始化塊為其指定初始值。JVM會按他們的順序執行。這個地方需要注意:如上代碼,靜態變數staticInt最後會被賦值為3,因為靜態代碼塊在聲明之前。JVM是先跑到java.lang.class對象看有什麼靜態變數,給他分個空間,然後再執行的聲明和靜態代碼塊語句,因此初始化之後值為3.
好了,345都是類的載入和初始化,我們再來看看都做了些什麼:產生java.lang.class對象,有該類裡的屬性方法代碼塊的所有資訊。再為靜態屬性分配了記憶體並執行了靜態代碼塊,按
順序把靜態屬性給初始化了。這裡並沒有為非靜態屬性分配記憶體,也沒有執行建構函式和非靜態代碼塊,一句話
總結就是:記錄下這個類的所有屬性和方法代碼塊等資訊,為靜態變數分記憶體並賦值。
初始化之後,現在JVM改根據這個初始化好的類資訊來進行執行個體化了。先前被初始化好的靜態變數會被所有執行個體共用,靜態代碼塊將不會再被執行,相當於失效了。我們來看看JVM接下來要幹嘛?
6)JVM跑到java.lang.class對象裡看一看,有哪些執行個體變數需要分配記憶體的,跟靜態變數類似的,JVM先給執行個體變數分記憶體,分完之後,執行代碼塊和聲明,在這裡vInt為10。
7)最後執行建構函式,執行完後,vInt變成了20,staticInt變成了9,然後改建構函式隱性的返回一個Person執行個體對象給變數p。
好了,講完了,我們再看看12問題
1、類的載入和初始化神馬的和建構函式有啥關係和區別?
只要在類需要執行個體化的時候才會執行建構函式。而類的載入和初始化卻在這些情況都會被執行:建立執行個體 調用靜態方法 訪問某個靜態Field(如果該變數還是final的,則在編譯階段就能確定下來,就不會初始化) 初始化某個類子類
2、類的初始化會為執行個體屬性分配記憶體嗎?
不會為執行個體屬性分配,只有在執行個體化的時候才會分記憶體
總結
1)將類的class檔案讀入記憶體,並為之建立一個java.lang.class對象。
2)把類的位元據合并到JRE中,檢查被載入的類是否有正確的內部結構,並和其他類協調一致,並為靜態變數分記憶體
3)為靜態變數初始化賦值
以上為初始化順序
4)為非靜態變數分記憶體,並賦值
5)建構函式,返回構造好的對象
如果有子類父類別關係的時候:
父類和子類的class檔案都載入到記憶體,當父類,和子類有Static時,先初始化Static,再初始化子類的Static,
再初始化父類的其他成員變數->父類構造方法->子類其他成員變數->子類的構造方法。
有不對的地方還望高手指出啊
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
java類的初始化和建構函式