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
相關文章
- PHP類的靜態(static)方法和靜態(static)變數PHP變數
- Java | 靜態巢狀類(Static Nested Class)Java巢狀
- static靜態方法的使用
- java中static使用之靜態方法注意點Java
- static靜態變數的理解變數
- static變數,static程式碼塊,建構函式,程式碼塊等的載入順序變數C程式函式
- Java靜態程式碼塊Java
- 函式的靜態變數 static函式變數
- c#靜態類static class示例C#
- Flask 配置靜態資原始檔夾static_url_path、static_folderFlask
- 理解C#中靜態Static與單例SingletonC#單例
- PHP 中 static 靜態屬性和靜態方法的呼叫PHP
- Java靜態static工具類執行緒安全問題研究Java執行緒
- java的static塊執行時機Java
- Django 教程之media和static靜態檔案Django
- C++ static variable(靜態變數) 學習C++變數
- 靜態化與伺服器渲染(Static vs. Server Rendering)伺服器Server
- static程式碼塊、構造程式碼塊、建構函式以及Java類初始化順序C程式函式Java
- 靜態程式碼塊
- Java之StaticJava
- 關於Static程式碼塊、匿名程式碼塊、構造器的小擴充C程式
- PHP延遲靜態繫結:static關鍵字PHP
- 手寫koa-static原始碼,深入理解靜態伺服器原理原始碼伺服器
- Java中靜態程式碼塊、構造程式碼塊、建構函式、普通程式碼塊Java函式
- Java中static、final、static final的區別Java
- static 靜態變數引起 Laravel 中佇列一個 Bug變數Laravel佇列
- SpringBoot static 靜態方法獲取 yml 配置檔案Spring Boot
- PHP 手冊 (類與物件) 學習筆記九:Static(靜態)關鍵字PHP物件筆記
- 理解靜態區域性變數(static)在程式中的執行規則變數
- java中的Static、final、Static final各種用法Java
- Java static方法塊只獲取一次物件控制程式碼供全域性使用Java物件
- Java基礎——static 靜靜地隨著類的載入而載入Java
- static
- new self()與new static()
- 靜態程式碼塊、構造程式碼塊、構造方法構造方法
- 物件與引用,static關鍵字,程式碼塊,包,訪問許可權修飾符物件訪問許可權
- Java中建構函式、靜態程式碼塊、程式碼塊的執行順序Java函式
- Java普通程式碼塊,構造程式碼塊,靜態程式碼塊區別,執行順序的程式碼例項Java