本人小白一枚,看java類的初始化的時候好暈的說,我覺着書上儘管說的對。但總認爲有些信息沒說出來,沒說清楚,看了好多文章博客的,現在有些感悟,來小寫下總結,也算是爲之後再次複習種個好果子。java
先摘一下書上寫的:函數
載入:將類的class文件讀入內存,併爲之建立一個java.lang.class對象。spa
鏈接:把類的二進制數據合併到JRE中,檢查被載入的類是否有正確的內部結構,並和其它類協調一致。爲類的靜態FIELD分配內存,設置默認值,將類的二進制數據中的符號引用替換成直接引用。指針
初始化:主要對靜態Field進行初始化。初始化方式兩種:聲明靜態Field時指定的值。使用靜態初始化塊爲其指定初始值。JVM會按他們的順序運行。初始化包含下面步驟:
若是該類沒有被載入和鏈接。則先載入並鏈接該類。
若是他的父類沒有被初始化。則先初始化他的父類
若是類中有初始化語句,則系統依次運行。對象
看完以後我腦子裏一直就盤旋着幾個問題:內存
一、類的載入和初始化神馬的和構造函數有啥關係和差異?博客
二、類的初始化會爲實例屬性分配內存嗎?it
三、假設我要建立一個實例對象。到底是怎麼個建立流程?編譯
OK,假設你也有以上的疑問,那麼咱們一塊兒來看看到底是怎麼回事!我會直接回答最後一個問題,當你把這個問題弄明確了,前面的就迎刃而解了。class
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問題
一、類的載入和初始化神馬的和構造函數有啥關係和差異?
僅僅要在類需要實例化的時候纔會運行構造函數。而類的載入和初始化卻在這些狀況都會被運行:建立實例 調用靜態方法 訪問某個靜態Field(假設該變量仍是final的,則在編譯階段就能肯定下來,就不會初始化) 初始化某個類子類
二、類的初始化會爲實例屬性分配內存嗎?
不會爲實例屬性分配,僅僅有在實例化的時候纔會份內存
總結
1)將類的class文件讀入內存,併爲之建立一個java.lang.class對象。
2)把類的二進制數據合併到JRE中。檢查被載入的類是否有正確的內部結構。並和其它類協調一致,併爲靜態變量份內存
3)爲靜態變量初始化賦值
以上爲初始化順序
4)爲非靜態變量份內存。並賦值
5)構造函數,返回構造好的對象
假設有子類父類關係的時候:
父類和子類的class文件都載入到內存,當父類。和子類有Static時。先初始化Static,再初始化子類的Static,
再初始化父類的其它成員變量->父類構造方法->子類其它成員變量->子類的構造方法。
有不正確的地方還望高手指出啊