與的區別

可能出現在class文件中的兩種編譯器產生的方法是:實例初始化方法(名爲<init>)和類與接口初始化方法(名爲<clinit>)。

 

這兩種方法有什麼區別呢?

首先:這兩個方法一個是虛擬機在裝載一個類初始化的時候調用的(clinit)。另一個是在類實例化時調用的(init)

 

首先說說類的初始化:

在Java代碼中,一個正確的初始值是通過類變量初始化語句或者靜態初始化語句給出的。一個類變量初始化語句是

變量聲明後的等號和表達式:

Java代碼  收藏代碼
  1. class Example {  
  2.        static int size = 3 * (int) (Math.random() * 5.0);  
  3. }  

 

靜態初始化語句是一個以static開頭的語句塊:

Java代碼  收藏代碼
  1. class Example{  
  2.      static int size;  
  3.      static {  
  4.            size = 3 * (int) (Math.random() * 5.0);  
  5.      }  
  6. }  

 所有的類變量初始化語句和類型的靜態初始化語句都被Java編譯器收集到了一起,放在一個特殊的方法中。這個方法就是<clinit>。

<clinit>不是類必須的方法,比如如果一個類中沒有靜態塊或者靜態成員變量,那麼編譯器就不會爲這個類生成<clinit>方法。

父類的<clinit>方法先於子類的<clinit>方法,虛擬機會保證在子類的<clinit>執行之前父類的<clinit>方法一定執行過了,說明虛擬機中第一個執行的是Object的<clinit>方法。

接口中不能使用靜態代碼塊,但是可以使用靜態成員變量,所以接口中可以存在<clinit>方法。執行接口中的<clinit>方法不必要限制性父接口中的<clinit>方法,只有當父接口中的靜態成員變量被使用時纔會執行父類的<clinit>方法。實現類初始化時也不一定會執行接口中的<clinit>方法。

虛擬機會保證在多線程的環境中,一個類的<clinit>方法被正確的加鎖、同步,只會有一個線程去初始化一個累,因此只有一個線程會執行這個類的<clinit>方法,其他線程阻塞等待。

 

我們在來看看<init>這個方法:

<init>方法是在一個類進行對象實例化時調用的。實例化一個類有四種途徑:調用new操作符;調用Class或java.lang.reflect.Constructor對象的newInstance()方法;調用任何現有對象的clone()方法;通過java.io.ObjectInputStream類的getObject()方法反序列化。

 

Java編譯器會爲它的每一個類都至少生成一個實例初始化方法。在Class文件中,被稱爲"<init>"

 

<clinit>是用於初始化靜態的類變量, <init>是初始化實例變量!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章