先引入一份代碼:
public class A{
public A(){
System.out.println("構造方法中a=30");
a=30;
}
{
System.out.println("構造代碼塊1中a=40");
a=40;
}
int a=init();
{
System.out.println("構造代碼塊2中a=60");
a=60;
}
public int init(){
System.out.println("初始化中a=90");
return 90;
}
static{
System.out.println("靜態代碼塊1中B=100");
B=100;
}
static int B=staticInit();
static{
System.out.println("靜態代碼塊2中B=400");
B=400;
}
public static int staticInit(){
System.out.println("初始化中B=500");
return 500;
}
public static void main(String[] args){
A p=new A();
A q=new A();
}
}
輸出結果爲:
靜態代碼塊1中B=100
初始化中B=500
靜態代碼塊2中B=400
構造代碼塊1中a=40
初始化中a=90
構造代碼塊2中a=60
構造方法中a=30
構造代碼塊1中a=40
初始化中a=90
構造方法中a=30
根據以上的運行結果我們會不由自主的產生幾個問題,例如:
1.什麼是靜態代碼塊?
所謂的代碼塊就是一段獨立的代碼空間,那什麼是靜態代碼塊呢?說白了,靜態代碼塊就是用static修飾的代碼塊。
2.它們的執行順序是什麼?
執行順序:(優先級從高到低)靜態代碼塊>mian方法>構造代碼塊>構造方法。
3.爲什麼在顯示結果中靜態代碼塊的內容只顯示了一次?
在類加載的init階段,類的類構造器中會收集所有的static塊和字段並執行,static塊只執行一次,由JVM保證其只執行一次。或者可以這樣認爲:static代碼塊只在類加載時執行,類是用類加載器來讀取的,類加載器是帶有一個緩存區的,它會把讀取到的類緩存起來,所以在一次虛擬機運行期間,一個類只會被加載一次,這樣的話靜態代碼塊只會運行一次。
4.靜態代碼塊的顯著特點是什麼?
隨着類的加載而執行,而且只執行一次
5.static{ }(靜態代碼塊)與{ }(非靜態代碼塊)的異同點
相同點:都是在JVM加載類時且在構造方法執行之前執行,在類中都可以定義多個。
不同點:靜態代碼塊在非靜態代碼塊之前執行(靜態代碼塊—>非靜態代碼塊—>構造方法)。
靜態代碼塊只在第一次new執行一次,之後不再執行,而非靜態代碼塊在每new
一次就執行一次。
總結:靜態代碼塊,在虛擬機加載類的時候就會加載執行,而且只執行一次;
非靜態代碼塊,在創建對象的時候(即new一個對象的時候)執行,每次創建對象都會執行一次
6.靜態代碼塊和靜態方法的區別?
1)靜態代碼塊是自動執行的; 靜態方法是被調用的時候才執行的。
2)靜態代碼塊可用來初始化一些項目最常用的變量或對象;靜態方法可用作不創建對象也可能需要執行的代碼。
7.關於靜態代碼塊的認識?
1)靜態代碼塊只能定義在類裏面,它獨立於任何方法,不能定義在方法裏面。
2)靜態代碼塊裏面的變量都是局部變量,只在本塊內有效。
3)靜態代碼塊會在類被加載時自動執行,而無論加載者是JVM還是其他的類。
4)一個類中允許定義多個靜態代碼塊,執行的順序根據定義的順序進行。
5)靜態代碼塊只能訪問類的靜態成員,而不允許訪問實例成員。實例方法可以訪問靜態和實例成員。
8.不允許靜態方法訪問實例成員變量的原因?
因爲實例成員變量是屬於某個對象的,而靜態方法在執行時,並不一定存在對象。
同樣,因爲實例方法可以訪問實例成員變量,如果允許靜態方法調用實例方法,將間接地允許它使用實例成員變量,所以靜態方法也不能調用實例方法。基於同樣的道理,靜態方法中也不能使用關鍵字this。
- 靜態代碼優先於非靜態的代碼的原因?
靜態代碼優先於非靜態的代碼,是因爲被static修飾的成員都是類成員,會隨着JVM加載類的時候加載而執行,而沒有被static修飾的成員也被稱爲實例成員,需要創建對象纔會隨之加載到堆內存。所以靜態的會優先非靜態的。
總結:
靜態代碼塊會隨着類的加載而執行,而且只執行一次。當所有的靜態代碼塊都執行結束後會執行main函數中的輸出語句,然後會去執行非靜態代碼塊,接着是執行構造方法。