本人小白一枚,看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,
再初始化父類的其它成員變量->父類構造方法->子類其它成員變量->子類的構造方法。
有不正確的地方還望高手指出啊