最后給大家一道面試題練練手,要求寫出其結果(筆試)
- public class StaticTest {
- public static int k = 0;
- public static StaticTest t1 = new StaticTest("t1");
- 代碼執行完這一行發生了什么?之所以會執行這行代碼,是main方法里面第一次 new的緣故,第一次new,會加載這個類的static變量,static方法(不執行)和static塊,因為 t1 是static,所以會執行這一行代碼 但 t1 這里又new了一個StaticTest對象,由於在main方法里面已經new了一個,所以這里new的不再加載static變量和塊,只初始化變量j,加載構造快和構造函數,在加載 j 時,又需要用到static變量 i 和 n ,但此時並未給 i 和 n 初始化(因為還沒有執行到給 i 和 n 初始化的代碼),所以此時的 i 和 n 用默認值 0 ! 我去。。。。
- 當代嗎執行到這時,jvm如何知道這已經是第二次new了?因為類加載過程中存在一個准備階段,這個階段是在方法區中為所有類變量賦初值(除了static final是直接賦了指定值);然后才到了類初始化階段,這里執行到new實際上是到了類初始化階段,這時方法區已經有了這個類的信息了,所以jvm才知道這不是第一次new;
注:main方法所在類,是被隱式初始化了,但沒有被實例化
- public static StaticTest t2 = new StaticTest("t2");
- public static int i = print("i");
- public static int n = 99;
- public int j = print("j");
- {
- print("構造塊");
- }
- static{
- print("靜態塊");
- }
- public StaticTest(String str) {
- System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
- ++n;
- ++i;
- }
- public static int print(String str) {
- System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
- ++i;
- return ++n;
- }
- public static void main(String[] args) {
- StaticTest t = new StaticTest("init");
- }
- }
結果:
- 1:j i=0 n=0
- 2:構造塊 i=1 n=1
- 3:t1 i=2 n=2
- 4:j i=3 n=3
- 5:構造塊 i=4 n=4
- 6:t2 i=5 n=5
- 7:i i=6 n=6
- 8:靜態塊 i=7 n=99
- 9:j i=8 n=100
- 10:構造塊 i=9 n=101
- 11:init i=10 n=102
這個留給大家去思考,如果一眼便能便知道為什么是這樣的輸出結果,那么靜態方面知識應該比較扎實了
感悟:
提示一下 :
1.加載的順序:先父類的static成員變量 -> 子類的static成員變量 -> 父類的成員變量 -> 父類構造 -> 子類成員變量 -> 子類構造
2.static只會加載一次,所以通俗點講第一次new的時候,所有的static都先會被全部載入(以后再有new都會忽略),進行默認初始化。在從上往下進行顯示初始化。這里靜態代碼塊和靜態成員變量沒有先后之分,誰在上,誰就先初始化
3.構造代碼塊是什么?把所有構造方法中相同的內容抽取出來,定義到構造代碼塊中,將來在調用構造方法的時候,會去自動調用構造代碼塊。構造代碼快優先於構造方法。
