類變量和實例變量及其初始化
0.基本概念
類變量是指java類中的static數據成員,實例變量則是指java類中的非static數據成員。由於類變量不需要創建一個對象即可訪問,而實例變量則必須與一個具體的對象對應,因此類變量和實例變量的初始化時機是不同的。本文主要關註以下3個問題:
(1)什麽時候初始化類變量?什麽時候初始化實例變量?
(2)什麽時候會同時初始化類變量和實例變量?
(3)在(1)、(2)情形下各個類變量和實例變量的初始化順序?
1.類變量初始化
根據有無被final關鍵字修飾,類變量的初始化時機不同。被final關鍵字修飾的類變量在編譯時就已經被初始化被放置在常量池中了,而沒有被final修飾的類變量則在該類首次使用時被初始化。特別需要註意的是,類變量只在該類首次使用時被初始化,這意味著類變量只會被初始化一次。
在下列情形下,如果一個java類中沒有被final修飾的類變量尚未初始化,那麽這些沒有被final修飾的類變量將會被初始化:
(1)訪問該類中沒有被final修飾的類變量時;
(2)設置該類中沒有被final修飾的類變量時;
(3)調用該類的static方法。
初始化順序確定規則:
(1)在上述3個情形下,首先會初始化該類中所有沒有被final修飾的類變量,然後再執行對應的操作;
(2)static變量初始化的方式有兩種:定義時初始化和static代碼塊中初始化。因此,在類變量初始化時機時(上述的3種情形)java虛擬機會按照代碼中的順序依次執行static變量定義語句和static代碼塊。(兩種初始化方式的示例代碼如下)
(3)如果該類有父類且父類的類變量沒有初始化,則先初始化父類的類變量。
1 class A(){ 2 public static final String STR = "hello";//final static變量,在編譯時被初始化 3 public static int i = 1;//static變量初始化方式一:在定義時初始化 4 static{//static變量初始化方式二:在static代碼塊初始化static變量 5 System.out.println("statci 代碼塊"); 6 } 7 }
根據上述的初始化順序確定規則,可以確定初始化順序如下:
//沒有繼承的情形 static變量初始化和static代碼塊 //有繼承的情形 1.父類的static變量初始化和static代碼塊 2.子類的static變量初始化和static代碼塊
2.實例變量初始化
實例變量初始化是在創建該類的對象時進行的,確定初始化順序的規則下:
(1)如果創建該類的對象時該類的類變量尚未初始化,則先初始化類變量,載初始化實例變量;
(2)如果該類有父類的話,則先創建一個父類對象;並且,如果父類類變量沒被初始化時,先初始化父類的類變量,再初始化父類的實例變量,再調用父類的默認構造器;
(3)如果父類還有父類的話,根據(2)的規則以此類推,一直到根基類。
根據上述初始化順序規則,可以確定的初始化順序如下:
//沒有繼承的情形 1.static變量初始化和static代碼塊 2.實例變量初始化和實例變量初始化代碼塊 3.構造函數 //有繼承的情形 有繼承的情形: 1.父類的static變量初始化和static代碼塊 2.子類的static變量初始化和static代碼塊 3.父類的實例變量初始化和實例變量初始化代碼塊 4.父類的構造函數 5.子類的實例變量初始化和實例變量初始化代碼塊 6.子類構造函數
3.實例
類變量和實例變量及其初始化