Java面向對象之初始化塊

Java面向對象之初始化塊

在程序設計中,讓數據域正確地執行初始化一直是一個亙古不變的真理。
那麼,有哪些手段能夠初始化數據域呢:測試

  • 在構造器中設置值。
  • 在聲明中賦值。
  • 使用初始化塊

本篇探討關於Java中的初始化塊的注意點:Java中的初始化塊是類中的一種成員,可是既沒有名字,也沒有標識,不可以被調用,它僅僅只是在建立Java對象時隱式執行初始化。this

普通初始化塊

  • 普通的初始化塊就是非static修飾的。
  • 聲明時以花括號{}包起代碼,被包住的就是初始化代碼,總體就是一個初始化塊。
  • 能夠有不少個初始化塊,按順序前後且所有地執行,因此沒什麼必要分開,一塊兒就完事。
  • 聲明實例變量時指定默認值普通初始化塊都被看作是對象的初始化代碼,按前後順序執行。設計

  • 初始化塊老是在構造器以前被調用
  • 若是多個重載的構造器有相同且與傳入形參無關的語句能夠一塊兒提入初始化塊。code

public class NormalBlock {
    int a = 5;
    {
//        a = 6;
        System.out.println("初始化塊以後的a爲"+a);
    }
//    {
//        int a = 8;
//        System.out.println("初始化塊中從新定義了一個a?"+a);
//    }
    NormalBlock(){

        System.out.println("構造器中賦a的值爲"+a);
    }
}
class NormalTest{
    public static void main(String[] args) {
        new NormalBlock();
    }
}
  • 上面註釋語句時,結果以下:
初始化塊以後的a爲5
構造器中賦a的值爲5

能夠看到,在這個例子中,聲明實例變量指定默認值也被看做初始化代碼,且依次執行,先初始化塊,後構造器。(能夠試着調換它們的位置驗證一下哈)orm

  • 上面解除註釋語句以後,我對結果是產生疑惑的:
初始化塊以後的a爲6
初始化塊中從新定義了一個a?8
構造器中賦a的值爲6

個人疑惑點在於,我一開始覺得,我在第二個代碼塊中定義的和以前同名的變量a是同一個(然而並非)這樣也就算了,初始化代碼以後,執行構造器時,調用了a,那麼這時這個a調用的是哪一個呢,因而產生疑惑,但願知道的小夥伴能夠爲我指點迷津對象

  • 我在測試的時候還遇到了ilegal forward reference,即前向引用錯誤,以下圖。
{
        age = 50;
        if(age>40) System.out.println("Father類的初始化塊且age>40");
        System.out.println("Father類的第一個初始化塊");
    }
    int age =20;

產生緣由:是由於在尚未定義該變量時,就引用了它,因此爲了不這樣的錯誤,儘可能將初始化塊放在成員變量聲明以後。繼承

靜態初始化塊

和普通的對應的就是靜態初始化塊啦,也就是用static修飾的,也稱爲類初始化塊。根據名稱分析,類初始化塊負責對類進行初始化,而普通初始化塊負責對對象執行初始化。it

  • static{}的格式包圍對類變量的初始化。
  • 因爲靜態初始化塊和類相關,負責對類進行初始化,因此老是比普通初始化塊先執行。
  • 一般用於對類變量執行初始化處理,而不能對實例變量進行初始化處理。
  • 靜態初始化塊屬於類的靜態成員,遵循靜態成員不能訪問非靜態成員的規則:即不能訪問非靜態成員(實例變量和實例方法)
  • 相似地,靜態初始化塊聲明靜態成員變量時指定初始值都時該類的初始化代碼。

初始化塊與構造器

關於初始化塊與構造器的前後調用順序,結合代碼來理解一會兒。程序設計

package com.my.pac17;

/**
 * @auther Summerday
 */
public class A {
    {
        System.out.println("A.instance initializer");
    }
    static {
        System.out.println("A.static initializer");
    }
    public A() {
        System.out.println("A.A");
    }
}
class B extends A {
    {
        System.out.println("B.instance initializer");
    }
    static {
        System.out.println("B.static initializer");
    }
    public B() {
        System.out.println("B.B");
    }
    public B(String m) {
        this();
        System.out.println("B.B," + m);
    }
}
class C extends B {
    {
        System.out.println("C.instance initializer");
    }
    static {
        System.out.println("C.static initializer");
    }
    public C() {
        super("ccc");
        System.out.println("C.C");
    }
}
class BTest {
    public static void main(String[] args) {
        new C();
        System.out.println("*******");
        new C();
    }
}
/*測試結果*/
A.static initializer
B.static initializer
C.static initializer
/*類初始化階段,限制性最頂層父類的靜態初始化塊
而後依次向下,直到執行當前類的靜態初始化塊*/
A.instance initializer
A.A
B.instance initializer
B.B//調用B的無參構造器
B.B,ccc//調用B的帶參構造器
C.instance initializer//最後執行C
C.C
/*對象初始化階段,先執行最頂層父類的初始化塊,
最頂層父類的構造器,而後依次向下,直到執行當前
類的初始化塊、當前類的構造器*/
*******
//不用執行靜態初始化語句
A.instance initializer
A.A
B.instance initializer
B.B
B.B,ccc
C.instance initializer
C.C
  • static修飾的靜態初始化塊,老是先被調用,且在繼承關係中,最先的父類中的靜態初始化塊先執行。
  • 能夠看到,第二次建立子類對象時,就沒有再執行靜態初始化塊中的初始化,由於三個類已經加載成功
  • 普通初始化塊和構造器的執行順序爲,普通初始化塊在構造器以前執行,從最先的父類一直到當前類。
相關文章
相關標籤/搜索