java static 與 static靜態程式碼塊
大家在去參加面試的時候,經常會遇到這樣的考題:給你兩個類的程式碼,它們之間是繼承的
關係,每個類裡只有構造器方法和一些變數,構造器裡可能還有一段程式碼對變數值進行了某
種運算,另外還有一些將變數值輸出到控制檯的程式碼,然後讓我們判斷輸出的結果。這實際
上是在考查我們對於繼承情況下類的初始化順序的瞭解。
我們大家都知道,對於靜態變數、靜態初始化塊、變數、初始化塊、構造器,它們的初始化
順序依次是(靜態變數、靜態初始化塊)>(變數、初始化塊)>構造器。我們也可以通過下
面的測試程式碼來驗證這一點:
Java 程式碼
public class InitialOrderTest {
// 靜態變數
public static String staticField = "靜態變數";
// 變數
public String field = "變數";
// 靜態初始化塊
static {
System.out.println(staticField);
System.out.println("靜態初始化塊");
}
// 初始化塊
{
System.out.println(field);
System.out.println("初始化塊");
}
// 構造器
public InitialOrderTest() {
System.out.println("構造器");
}
public static void main(String[] args) {
new InitialOrderTest();
}
}
執行以上程式碼,我們會得到如下的輸出結果:
1. 靜態變數
2. 靜態初始化塊
3. 變數
4. 初始化塊
5. 構造器
這與上文中說的完全符合。那麼對於繼承情況下又會怎樣呢?我們仍然以一段測試程式碼來獲
取最終結果:
Java程式碼 :
class Parent {
// 靜態變數
public static String p_StaticField = "父類--靜態變數";
// 變數
public String p_Field = "父類--變數";
// 靜態初始化塊
static {
System.out.println(p_StaticField);
System.out.println("父類--靜態初始化塊");
}
// 初始化塊
{
System.out.println(p_Field);
System.out.println("父類--初始化塊");
}
// 構造器
public Parent() {
System.out.println("父類--構造器");
}
}
public class SubClass extends Parent {
// 靜態變數
public static String s_StaticField = "子類--靜態變數";
// 變數
public String s_Field = "子類--變數";
// 靜態初始化塊
static {
System.out.println(s_StaticField);
System.out.println("子類--靜態初始化塊");
}
// 初始化塊
{
System.out.println(s_Field);
System.out.println("子類--初始化塊");
}
// 構造器
public SubClass() {
System.out.println("子類--構造器");
}
// 程式入口
public static void main(String[] args) {
new SubClass();
}
}
執行一下上面的程式碼,結果馬上呈現在我們的眼前:
1. 父類--靜態變數
2. 父類--靜態初始化塊
3. 子類--靜態變數
4. 子類--靜態初始化塊
5. 父類--變數
6. 父類--初始化塊
7. 父類--構造器
8. 子類--變數
9. 子類--初始化塊
10.子類--構造器
現在,結果已經不言自明瞭。大家可能會注意到一點,那就是,並不是父類完全初始化完畢
後才進行子類的初始化,實際上子類的靜態變數和靜態初始化塊的初始化是在父類的變數、
初始化塊和構造器初始化之前就完成了。
那麼對於靜態變數和靜態初始化塊之間、變數和初始化塊之間的先後順序又是怎樣呢?是否
靜態變數總是先於靜態初始化塊,變數總是先於初始化塊就被初始化了呢?實際上這取決於
它們在類中出現的先後順序。我們以靜態變數和靜態初始化塊為例來進行說明。
同樣,我們還是寫一個類來進行測試:
Java 程式碼
public class TestOrder {
// 靜態變數
public static TestA a = new TestA();
// 靜態初始化塊
static {
System.out.println("靜態初始化塊");
}
// 靜態變數
public static TestB b = new TestB();
public static void main(String[] args) {
new TestOrder();
}
}
class TestA {
public TestA() {
System.out.println("Test--A");
}
}
class TestB {
public TestB() {
關係,每個類裡只有構造器方法和一些變數,構造器裡可能還有一段程式碼對變數值進行了某
種運算,另外還有一些將變數值輸出到控制檯的程式碼,然後讓我們判斷輸出的結果。這實際
上是在考查我們對於繼承情況下類的初始化順序的瞭解。
我們大家都知道,對於靜態變數、靜態初始化塊、變數、初始化塊、構造器,它們的初始化
順序依次是(靜態變數、靜態初始化塊)>(變數、初始化塊)>構造器。我們也可以通過下
面的測試程式碼來驗證這一點:
Java 程式碼
public class InitialOrderTest {
// 靜態變數
public static String staticField = "靜態變數";
// 變數
public String field = "變數";
// 靜態初始化塊
static {
System.out.println(staticField);
System.out.println("靜態初始化塊");
}
// 初始化塊
{
System.out.println(field);
System.out.println("初始化塊");
}
// 構造器
public InitialOrderTest() {
System.out.println("構造器");
}
public static void main(String[] args) {
new InitialOrderTest();
}
}
執行以上程式碼,我們會得到如下的輸出結果:
1. 靜態變數
2. 靜態初始化塊
3. 變數
4. 初始化塊
5. 構造器
這與上文中說的完全符合。那麼對於繼承情況下又會怎樣呢?我們仍然以一段測試程式碼來獲
取最終結果:
Java程式碼 :
class Parent {
// 靜態變數
public static String p_StaticField = "父類--靜態變數";
// 變數
public String p_Field = "父類--變數";
// 靜態初始化塊
static {
System.out.println(p_StaticField);
System.out.println("父類--靜態初始化塊");
}
// 初始化塊
{
System.out.println(p_Field);
System.out.println("父類--初始化塊");
}
// 構造器
public Parent() {
System.out.println("父類--構造器");
}
}
public class SubClass extends Parent {
// 靜態變數
public static String s_StaticField = "子類--靜態變數";
// 變數
public String s_Field = "子類--變數";
// 靜態初始化塊
static {
System.out.println(s_StaticField);
System.out.println("子類--靜態初始化塊");
}
// 初始化塊
{
System.out.println(s_Field);
System.out.println("子類--初始化塊");
}
// 構造器
public SubClass() {
System.out.println("子類--構造器");
}
// 程式入口
public static void main(String[] args) {
new SubClass();
}
}
執行一下上面的程式碼,結果馬上呈現在我們的眼前:
1. 父類--靜態變數
2. 父類--靜態初始化塊
3. 子類--靜態變數
4. 子類--靜態初始化塊
5. 父類--變數
6. 父類--初始化塊
7. 父類--構造器
8. 子類--變數
9. 子類--初始化塊
10.子類--構造器
現在,結果已經不言自明瞭。大家可能會注意到一點,那就是,並不是父類完全初始化完畢
後才進行子類的初始化,實際上子類的靜態變數和靜態初始化塊的初始化是在父類的變數、
初始化塊和構造器初始化之前就完成了。
那麼對於靜態變數和靜態初始化塊之間、變數和初始化塊之間的先後順序又是怎樣呢?是否
靜態變數總是先於靜態初始化塊,變數總是先於初始化塊就被初始化了呢?實際上這取決於
它們在類中出現的先後順序。我們以靜態變數和靜態初始化塊為例來進行說明。
同樣,我們還是寫一個類來進行測試:
Java 程式碼
public class TestOrder {
// 靜態變數
public static TestA a = new TestA();
// 靜態初始化塊
static {
System.out.println("靜態初始化塊");
}
// 靜態變數
public static TestB b = new TestB();
public static void main(String[] args) {
new TestOrder();
}
}
class TestA {
public TestA() {
System.out.println("Test--A");
}
}
class TestB {
public TestB() {
System.out.println("Test--B");
執行上面的程式碼,會得到如下的結果:
1. Test--A
2. 靜態初始化塊
3. Test--B
大家可以隨意改變變數a、變數b以及靜態初始化塊的前後位置,就會發現輸出結果隨著它
們在類中出現的前後順序而改變,這就說明靜態變數和靜態初始化塊是依照他們在類中的定
義順序進行初始化的。同樣,變數和初始化塊也遵循這個規律。
瞭解了繼承情況下類的初始化順序之後,如何判斷最終輸出結果就迎刃而解了。
作者:臧圩人(zangweiren)
網址:http://zangweiren.javaeye.com
相關文章
- Java | 靜態巢狀類(Static Nested Class)Java巢狀
- static靜態方法的使用
- static變數,static程式碼塊,建構函式,程式碼塊等的載入順序變數C程式函式
- 延遲靜態繫結——static
- Java靜態程式碼塊Java
- Flask 配置靜態資原始檔夾static_url_path、static_folderFlask
- 靜態化與伺服器渲染(Static vs. Server Rendering)伺服器Server
- Django 教程之media和static靜態檔案Django
- static程式碼塊、構造程式碼塊、建構函式以及Java類初始化順序C程式函式Java
- 靜態程式碼塊
- 關於Static程式碼塊、匿名程式碼塊、構造器的小擴充C程式
- SpringBoot static 靜態方法獲取 yml 配置檔案Spring Boot
- java中的Static、final、Static final各種用法Java
- ES6中類的靜態方法=> static 的使用
- Java中靜態程式碼塊、構造程式碼塊、建構函式、普通程式碼塊Java函式
- 手寫koa-static原始碼,深入理解靜態伺服器原理原始碼伺服器
- static 靜態變數引起 Laravel 中佇列一個 Bug變數Laravel佇列
- PHP 手冊 (類與物件) 學習筆記九:Static(靜態)關鍵字PHP物件筆記
- 理解靜態區域性變數(static)在程式中的執行規則變數
- Java static方法塊只獲取一次物件控制程式碼供全域性使用Java物件
- 物件與引用,static關鍵字,程式碼塊,包,訪問許可權修飾符物件訪問許可權
- Nginx R31 doc-09-Serving Static Content 靜態內容Nginx
- new self()與new static()
- static
- Java中建構函式、靜態程式碼塊、程式碼塊的執行順序Java函式
- Java普通程式碼塊,構造程式碼塊,靜態程式碼塊區別,執行順序的程式碼例項Java
- Java的static修飾符Java
- [Java物件導向]static方法Java物件
- Java 的 static 關鍵字Java
- Java中static的含義Java
- C:static 關鍵字、靜態變數、跨類訪問資料變數
- Non-static method 'save(java.long.Object)' cannot be referenced from a static context.JavaObjectContext
- const與static的區別
- nginx gzip 與 gzip_staticNginx
- static用法
- vue-cli 2.x index.html 引入 static 靜態資源注意VueIndexHTML
- java中的static關鍵字Java
- Java中構造方法,構造程式碼塊和靜態程式碼塊執行順序詳解Java構造方法
- java靜態程式碼檢測-pmdJava