解釋:為什麼列舉類的靜態程式碼塊再例項程式碼塊之後?????
阿新 • • 發佈:2022-05-15
/** * 只有繼承關係才會按照樹的初始化步驟進行, * 樹的初始化,各個部分執行先後順序,總是先初始化靜態樹,在初始化例項樹 * 初始化靜態樹: 總體上從Object到目標類,區域性上靜態變數和靜態程式碼塊按先後順序, * 初始化例項樹: 總體上從Object到目標類,區域性上例項變數和例項程式碼塊按先後順序,再執行構造器 * 內部類的例項化也是按照如上規則進行的,有一點不太理解,似乎列舉有一些不同,程式碼如下 * * 為什麼列舉類的靜態程式碼塊再例項程式碼塊之後????? * * 本人水平有限,做了如下測試,現在建立一個A類,並且保證A類程式碼和C列舉幾乎一樣,如下 * 1 給A類宣告例項變數SUMMER,用public static final修飾(列舉的例項也是如此,而且是預設的) * 2 給A提供無參的構造器和例項程式碼塊 * 3 在A的靜態程式碼塊裡給SUMMER建立一個A的例項變數賦值給它(唯一明顯的區別) * 點選執行,哇輸出結果居然也一樣,大家看出了什麼??好像把A類幾乎改造成了一個列舉類. * * 如下揣測: * 1 現在知道終於為什麼列舉的例項預設public static final修飾了, * 因為final的靜態成員變數,要麼宣告時賦值,要麼在靜態程式碼塊裡,而且final型別的變數有保證了它的不可變性 * 2 列舉類其實就是把成員變數放在靜態程式碼塊裡顯式賦值執行初始化了.就像在A的靜態程式碼塊裡出現的SUMMER = new A(); * 現在正好解釋了開頭我的疑問:為什麼列舉類的靜態程式碼塊再例項程式碼塊之後????? * 比如列舉類C在靜態程式碼塊裡顯式建立了一個該類的物件並且賦值了例項變數SPRING,造成了例項程式碼塊與靜態程式碼塊同步. * 3 列舉其實就是普通類(從它預設繼承Enum也可以看出),但不能當成完全當成普通類去用 * (想一想@interface註解和interface介面也是一樣,註解預設繼承了Annotation介面,但不能當成完全當成介面去用) * 4 人家設計列舉類就是希望這類的例項的個數有限而且是確定的.所以連構造器都是private的,而且加入它一些特殊的語法 * * */ //解釋:為什麼列舉類的靜態程式碼塊再例項程式碼塊之後????? public class EnumQuestion { public static void main(String[] args) throws Exception{ System.out.println(C.SPRING); System.out.println("====================="); System.out.println(A.SUMMER); /**執行程式碼如下 * * 我是C的例項程式碼塊 * 我是C的構造器 * 我是C的靜態程式碼塊 * SPRING * ===================== * 我是A的例項程式碼塊 * 我是A的參構造器 * 我是A的靜態程式碼塊 * com.china.school.疑問.A@2133c8f8 */ } } enum C { SPRING; static { System.out.println("我是C的靜態程式碼塊"); } { System.out.println("我是C的例項程式碼塊"); } C(){ System.out.println("我是C的構造器"); } } class A{ public static final A SUMMER ; public A(){ System.out.println("我是A的參構造器"); } { System.out.println("我是A的例項程式碼塊"); } static { SUMMER = new A(); System.out.println("我是A的靜態程式碼塊"); } }