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,

再初始化父類的其它成員變量->父類構造方法->子類其它成員變量->子類的構造方法。

有不正確的地方還望高手指出啊



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM