摘要:靜態塊代碼初始化其實,整個靜態代碼塊可以看作是一個靜態成員。和普通的非靜態成員初始化一樣,它的執行也發生在構造器調用之前,并且每當創建對象之前都會調用。口繼承中涉及的初始化大的原則是沒有父類,就沒子類。
這個教程,咱們來對Java中設計到的初始化規則,或者說初始化順序,來做一下匯總,這里我基本上把Java中,默認初始化,靜態成員初始化,非靜態成員初始化,靜態代碼塊,非靜態代碼塊,以及繼承中所涉及到的初始化,都涵蓋全了。希望你看到這個教程,能有所收獲。(?′?`?)
默認初始化在Java中,一個類的數據成員(成員變量)如果沒有指定初始化,那么Java會對其執行默認初始化。
基本類型初始化默認值為0,boolean為false,字符串或者對象引用初始化為null。這部分比較簡單,看下面這個小列子,相信你應該能直接看出來最后運行的結果。(<_<)
public class InitialValues { boolean t; char c; short s; int i; long l; float f; double d; String str; InitialValues reference; void printInitialValues() { System.out.printf("%-10s %-5s ", "boolean:", t); System.out.printf("%-10s %-5s ", "char:", c); System.out.printf("%-10s %-5s ", "short:", s); System.out.printf("%-10s %-5s ", "int:", i); System.out.printf("%-10s %-5s ", "long:", l); System.out.printf("%-10s %-5s ", "float:", f); System.out.printf("%-10s %-5s ", "double:", d); System.out.printf("%-10s %-5s ", "String:", str); System.out.printf("%-10s %-5s ", "reference:", reference); } public static void main(String[] args) { InitialValues iv = new InitialValues(); iv.printInitialValues(); } }
// Output ---------------- boolean: false char: short: 0 int: 0 long: 0 float: 0.0 double: 0.0 String: null reference: null非靜態成員初始化順序
在一個類中,非靜態成員的初始化,發生在任何方法(包括構造器)被調用之前。并且它們定義的順序,決定了初始化的順序。來看下面這個小程序,這里的類,我都用的通用的無實際意義的類,這樣能讓咱們把注意力放在代碼邏輯上。這個小程序,我給你提點要求:你捋一下代碼的邏輯,看看能不能直接寫出來最后的運行結果。完了把你寫的結果和我后面給你的答案對比一下,看看能不能搞對。最后你自己最好能敲敲程序運行一下。( ??⊿??)?
class XXX { XXX(String s){ System.out.println("XXX > " + s); } } class AAA { XXX x001 = new XXX("001"); AAA() { System.out.println("AAA"); XXX x004 = new XXX("004"); } XXX x002 = new XXX("002"); void fff() { System.out.println("fffffffff"); } XXX xxx003 = new XXX("003"); } public class Initialization { public static void main(String[] args) { AAA aaa = new AAA(); aaa.fff(); } }
// Output --------- XXX > 001 XXX > 002 XXX > 003 AAA XXX > 004 fffffffff靜態成員初始化及對象的創建過程
以名為YYY的類舉例:
當該類的靜態方法(包括main()和構造器,構造器實際上也是靜態方法)或者靜態成員被調用或訪問時,Java虛擬機將載入類所對應的YYY.class文件,并創建其Class類對象,然后該類所有的靜態成員將執行初始化。并且靜態成員初始化只執行這一次。
靜態初始化完成后,該類就做好了創建對象的準備。當調用new YYY()創建對象的時候,首先在堆內存上為YYY對象分配空間,然后執行默認初始化(基本類型初始化為0,引用類型初始化為null)。
之后,按照非靜態成員定義順序,進行指定初始化。
最后執行構造器,完成對象的創建。
還是和上面同樣的要求,先捋代碼邏輯,再手寫結果。 (`?ω?′)ゞ
class XXX { XXX(String s){ System.out.println("XXX > " + s); } void xox(String s){ System.out.println("xox : " + s); } } class AAA { XXX x001 = new XXX("001"); static XXX x002 = new XXX("002"); AAA() { System.out.println("AAA"); x002.xox("002"); } void aaa() { System.out.println("aaa"); } } class BBB { static XXX x003 = new XXX("003"); XXX x004 = new XXX("004"); BBB(){ System.out.println("BBB"); x004.xox("004"); } void bbb(){System.out.println("bbb");} } public class Initialization { public static void main(String[] args) { System.out.println("*********"); new AAA(); System.out.println("========="); new BBB(); a002.aaa(); b002.bbb(); } AAA a001 = new AAA(); static AAA a002 = new AAA(); static AAA a003= new AAA(); BBB b001 = new BBB(); static BBB b002 = new BBB(); static BBB b003 = new BBB(); }
// Output --------- XXX > 002 XXX > 001 AAA xox : 002 XXX > 001 AAA xox : 002 XXX > 003 XXX > 004 BBB xox : 004 XXX > 004 BBB xox : 004 ********* XXX > 001 AAA xox : 002 ========= XXX > 004 BBB xox : 004 aaa bbb靜態塊代碼初始化
其實,整個static { 靜態代碼塊 } 可以看作是一個靜態成員。當一個類需要執行靜態初始化時,該類中的靜態成員初始化和靜態代碼塊,會按照先后定義的順序執行。當然,這個流程也是就執行這一次。?⊙□⊙╱ 還是老要求......
class XXX { XXX(String s){ System.out.println("XXX > " + s); } } class AAA { XXX x001 = new XXX("001"); static XXX x002 = new XXX("002"); static XXX x003, x004; static { System.out.println("*********"); x003 = new XXX("003"); x004 = new XXX("004"); XXX x005 = new XXX("005"); System.out.println("========="); /**System.out.println(x006);*/ } static XXX x006 = new XXX("006"); XXX x007 = new XXX("007"); AAA() { System.out.println("AAA"); } } public class Initialization { static AAA aaa = new AAA(); public static void main(String[] args) { new AAA(); } }
// Output --------- XXX > 002 ********* XXX > 003 XXX > 004 XXX > 005 ========= XXX > 006 XXX > 001 XXX > 007 AAA XXX > 001 XXX > 007 AAA 假如把上面/**System.out.println(x006);*/注釋掉的代碼解除注釋,再運行程序,會發生什么情況?非靜態代碼塊初始化
{ 非靜態代碼塊 },可以看作一個非靜態成員。涉及非靜態初始化,也會執行它。和普通的非靜態成員初始化一樣,它的執行也發生在構造器調用之前,并且每當創建對象之前都會調用。
稍微修改下上面的例子,把靜態代碼塊前面的static關鍵字去掉,并把里面的注釋行釋放,并添加一行打印語句,如下,對比兩個例子輸出結果。(=??口??=)
class XXX { XXX(String s){ System.out.println("XXX > " + s); } } class AAA { XXX x001 = new XXX("001"); static XXX x002 = new XXX("002"); static XXX x003, x004; { System.out.println("*********"); x003 = new XXX("003"); x004 = new XXX("004"); XXX x005 = new XXX("005"); System.out.println("========="); System.out.println(x006); System.out.println(x001); } static XXX x006 = new XXX("006"); XXX x007 = new XXX("007"); AAA() { System.out.println("AAA"); } } public class Initialization { static AAA aaa = new AAA(); public static void main(String[] args) { new AAA(); } }
// Output ------------- XXX > 002 XXX > 006 XXX > 001 ********* XXX > 003 XXX > 004 XXX > 005 ========= XXX@1540e19d XXX@677327b6 XXX > 007 AAA XXX > 001 ********* XXX > 003 XXX > 004 XXX > 005 ========= XXX@1540e19d XXX@14ae5a5 XXX > 007 AAA繼承中涉及的初始化
大的原則是:沒有父類,就沒子類。初始化,當然要先初始化父類,再初始化子類。
繼承中如果同時涉及到靜態初始化和非靜態初始化。初始化的執行流程分兩步走:
(1)先執行靜態初始化。且先靜態初始化父類,然后再靜態初始化子類。(這一步同樣就執行一次)
(2)父類執行非靜態初始化,然后調用構造方法。接著子類執行非靜態初始化,然后調用構造方法。接著下一個子類......以此類推到最后一個子類。 (??ω?? 」∠)
class XXX { XXX(String s){ System.out.println("XXX > " + s); } } class AAA { XXX x001 = new XXX("001"); static XXX x002 = new XXX("002"); AAA() { System.out.println("AAA"); } { System.out.println("*********"); XXX x003 = new XXX("003"); } static XXX x004; static { System.out.println("========="); x004 = new XXX("004"); } static XXX x005 = fff("005"); static XXX fff(String s) { System.out.println("fffffffff"); return new XXX(s); } } class BBB extends AAA { static XXX x006 = new XXX("006"); XXX x007= new XXX("007"); { System.out.println("+++++++++"); XXX x008 = new XXX("008"); } static XXX x009; static { System.out.println("$$$$$$$$$"); x009 = new XXX("009"); } BBB(){ System.out.println("BBB"); } static XXX x010 = fff("010"); } public class Initialization { public static void main(String[] args) { new BBB(); new BBB(); } }
// Output --------- XXX > 002 ========= XXX > 004 fffffffff XXX > 005 XXX > 006 $$$$$$$$$ XXX > 009 fffffffff XXX > 010 XXX > 001 ********* XXX > 003 AAA XXX > 007 +++++++++ XXX > 008 BBB XXX > 001 ********* XXX > 003 AAA XXX > 007 +++++++++ XXX > 008 BBB
拓展一下,假如把上面的父類AAA改為抽象類,運行結果還一樣嗎?自己求證一下吧。
好,暫時先寫這么多,希望多多少少幫到了你點什么,后面我想到有需要補充的,我再更新帖子吧。??ヽ(?▽?)ノ?
============================================================================
有條件的小伙伴,可以給打賞點兒支持下,給我些鼓勵繼續寫下去。 (?′?`??)??
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://m.specialneedsforspecialkids.com/yun/76368.html
摘要:總結動態代理的相關原理已經講解完畢,接下來讓我們回答以下幾個思考題。 【干貨點】 此處是【好好面試】系列文的第12篇文章。文章目標主要是通過原理剖析的方式解答Aop動態代理的面試熱點問題,通過一步步提出問題和了解原理的方式,我們可以記得更深更牢,進而解決被面試官卡住喉嚨的情況。問題如下 SpringBoot默認代理類型是什么 為什么不用靜態代理 JDK動態代理原理 CGLIB動態代理...
摘要:后來知道有了院賽,學長說刷院和杭電就可,我就一直刷院,到最后比賽前院的前五十道基本做完,杭電也弄了十來道,就這樣草草參加比賽了。 博客主頁: https://b...
摘要:微信在上一個大版本中將公眾號內容的展示更改為信息流模式??酥频呐υ诒救丝磥恚⑿诺漠a品思維真得堪稱楷模。你可以仿照微信來搞一個公眾號,但如果不懂這些底層的邏輯,即便是輸了都不知道輸在哪里。 微信在上一個大版本中將公眾號內容的展示更改為信息流模式。剛開始還有些不習慣,也不明白為什么要這樣做。在使用了一段時間之后,慢慢也就習慣了。但在使用的某一瞬間,潛意識中有一個疑惑:同樣是推文,為什么...
摘要:與此相對,強類型語言的類型之間不一定有隱式轉換。三為什么是弱類型弱類型相對于強類型來說類型檢查更不嚴格,比如說允許變量類型的隱式轉換,允許強制類型轉換等等。在中,加性運算符有大量的特殊行為。 從++[[]][+[]]+[+[]]==10?深入淺出弱類型JS的隱式轉換 本文純屬原創? 如有雷同? 純屬抄襲? 不甚榮幸! 歡迎轉載! 原文收錄在【我的GitHub博客】,覺得本文寫的不算爛的...
閱讀 2184·2021-11-24 09:39
閱讀 2805·2021-07-29 13:49
閱讀 2329·2019-08-29 14:15
閱讀 2244·2019-08-29 12:40
閱讀 3325·2019-08-26 13:42
閱讀 644·2019-08-26 12:13
閱讀 2077·2019-08-26 11:41
閱讀 3356·2019-08-23 18:32