您好,登錄后才能下訂單哦!
類文件加載的順序
1、先加載執行父類的靜態變量及靜態初始化塊(執行先后順序按排列的先后順序)
2、再加載執行本類的靜態變量及靜態初始化塊
只要類沒有被銷毀,靜態變量及靜態初始化塊只會執行1次,后續再對該類進行其他操作也不會再執行這兩個步驟。
類實例創建過程
只有在調用new方法時才會創建類的實例
1、按照上面類文件加載的順序(類已被加載則跳過此步)
2、父類的非靜態變量及非靜態初始化塊
3、父類的構造方法
4、本類的非靜態變量及非靜態初始化塊
5、本類的構造方法
4、類實例銷毀時候,首先銷毀子類部分,再銷毀父類部分
靜態方法和非靜態方法都是被動調用
即系統不會自動調用執行。所以用戶沒有調用時都不執行,主要區別在于靜態方法可以直接用類名直接調用(實例化對象也可以),而非靜態方法只能先實例化對象后才能調用。
相關概念
static關鍵字:
是一個修飾符,用于修飾成員(成員變量和成員函數)
被修飾后的成員具備以下特點:
隨著類的加載而加載(類一加載,靜態數據就立即在內存中加載空間)
隨著類的消失而消失,說明它的生命周期最長
優先于對象存在(對象消失了,static還在)
靜態先存在,對象后存在
被所有對象所共享
節約內存空間
當成員被靜態修飾后,除了可以被對象調用外,還可以直接被類名調用
寫法:類名.靜態成員
使用注意
靜態方法只能訪問靜態成員(方法和變量)
非靜態方法既可以訪問靜態也可以訪問非靜態
靜態方法中不可以寫this,super關鍵字
因為靜態優先于對象存在,所以靜態方法中不可以出現this
主函數是靜態的
publicstaticvoidmain(String[]args){}
何時使用靜態?
要從兩方面下手:因為靜態修飾的內容有成員變量和函數。
何時定義靜態變量(類變量)
當對象中出現共享數據時,該數據被靜態所修飾。對象中的特有數據要定義成非靜態存在于堆內存中。
何時定義靜態函數
當功能內部沒有訪問到非靜態數據(對象特有數據),該功能可以定義成靜態。
靜態利弊
利:
1、對對象的共享數據單獨空間的存儲,節省空間。沒有必要每個對象都存儲一份。
2、可以直接被類名調用
弊:
1、生命周期過長
2、訪問出現局限性(只能訪問靜態)
內存結構
Java程序在運行時,需要在內存中的分配空間。為了提高運算效率,有對空間進行了不同區域的劃分,因為每一片區域都有特定的處理數據方式和內存管理方式。
棧內存
用于存儲局部變量當數據使用完,所占空間會自動釋放
堆內存
數組和對象(實體),通過new建立的實例都存放在堆內存中(成員變量隨著對象的建立而建立,存在于對象所在的堆內存中)每一個實體都有內存地址值(變量通過地址引用)實體中的變量都有默認初始化值實體不再被使用,會在不確定的時間內被垃圾回收器回收(垃圾回收機制)
方法區,本地方法區,寄存器
驗證
加載順序 | 父類靜態變量=1 | 父類非靜態變量=1 | 子類靜態變量=1 | 子類非靜態變量=1 |
---|---|---|---|---|
【父類調用父類靜態方法】 | Parent.pStaticMethod(); | |||
父類靜態初始化塊一 | 2 | |||
父類靜態初始化塊二 | 3 | |||
父類靜態方法 | 4 | |||
【子類調用子類靜態方法】 | Child.cStaticMethod(); | |||
子類靜態初始化塊一 | 5 | 2 | ||
子類靜態初始化塊二 | 6 | 3 | ||
子類靜態方法 | 7 | 4 | ||
【子類實例化】 | Child c=new Child(); | |||
父類非靜態初始化塊一 | 8 | 2 | ||
父類非靜態初始化塊二 | 9 | 3 | ||
父類構造方法 | 10 | 4 | ||
子類非靜態初始化塊一 | 11 | 5 | 5 | 2 |
子類非靜態初始化塊二 | 12 | 6 | 6 | 3 |
子類構造方法 | 13 | 7 | 7 | 4 |
【父類實例化子類對象】 | Parent p=new Child(); | |||
父類非靜態初始化塊一 | 14 | 2 | ||
父類非靜態初始化塊二 | 15 | 3 | ||
父類構造方法 | 16 | 4 | ||
子類非靜態初始化塊一 | 17 | 5 | 8 | 2 |
子類非靜態初始化塊二 | 18 | 6 | 9 | 3 |
子類構造方法 | 19 | 7 | 10 | 4 |
加載順序 | 父類靜態變量=1 | 父類非靜態變量=1 | 子類靜態變量=1 | 子類非靜態變量=1 |
---|---|---|---|---|
【子類實例化】 | Child c=new Child(); | |||
父類靜態初始化塊一 | 2 | |||
父類靜態初始化塊二 | 3 | |||
子類靜態初始化塊一 | 4 | 2 | ||
子類靜態初始化塊二 | 5 | 3 | ||
父類非靜態初始化塊一 | 6 | 2 | ||
父類非靜態初始化塊二 | 7 | 3 | ||
父類構造方法 | 8 | 4 | ||
子類非靜態初始化塊一 | 9 | 5 | 4 | 2 |
子類非靜態初始化塊二 | 10 | 6 | 5 | 3 |
子類構造方法 | 11 | 7 | 6 | 4 |
【父類實例化子類對象】 | Parent p=new Child(); | |||
父類非靜態初始化塊一 | 12 | 2 | ||
父類非靜態初始化塊二 | 13 | 3 | ||
父類構造方法 | 14 | 4 | ||
子類非靜態初始化塊一 | 15 | 5 | 7 | 2 |
子類非靜態初始化塊二 | 16 | 6 | 8 | 3 |
子類構造方法 | 17 | 7 | 9 | 4 |
【父類調用父類靜態方法】 | Parent.pStaticMethod(); | |||
父類靜態方法 | 18 | |||
【子類調用子類靜態方法】 | Child.cStaticMethod(); | |||
子類靜態方法 | 19 | 10 |
public class ClassTest { public static void main (String args[]) { System.out.println("【子類實例化】|Child c=new Child();"); Child c=new Child(); System.out.println("【父類實例化子類對象】|Parent p=new Child();"); Parent p=new Child(); System.out.println("【父類調用父類靜態方法】|Parent.pStaticMethod();"); Parent.pStaticMethod(); System.out.println("【子類調用子類靜態方法】|Child.cStaticMethod();"); Child.cStaticMethod(); } }
public class ClassTest2 { public static void main (String args[]) { System.out.println("【父類調用父類靜態方法】|Parent.pStaticMethod();"); Parent.pStaticMethod(); System.out.println("【子類調用子類靜態方法】|Child.cStaticMethod();"); Child.cStaticMethod(); System.out.println("【子類實例化】|Child c=new Child();"); Child c=new Child(); System.out.println("【父類實例化子類對象】|Parent p=new Child();"); Parent p=new Child(); } }
public class Parent { // 父類靜態變量 static int m = 1; // 父類非靜態變量 int n = 1; // 靜態語句塊1 static { m++; // j++; 父類非靜態變量不能在靜態語句塊中使用 System.out.println("父類靜態初始化塊一|" + m); } // 靜態語句塊2 static { m++; System.out.println("父類靜態初始化塊二|" + m); } // 構造函數 public Parent() { m++; n++; System.out.println("父類構造方法|" + m + "|" + n); } // 非靜態語句塊 { m++; n++; System.out.println("父類非靜態初始化塊一|" + m + "|" + n); } // 非靜態語句塊 { m++; n++; System.out.println("父類非靜態初始化塊二|" + m + "|" + n); } // 非靜態方法 public void pMethod() { m++; n++; System.out.println("父類非靜態方法|" + m + "|" + n); return; } // 靜態方法 public static void pStaticMethod() { m++; // j++; 父類非靜態變量不能在靜態方法中使用 System.out.println("父類靜態方法|" + m); return; } @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("銷毀父類|"); } }
public class Child extends Parent { // 靜態變量 static int i = 1; // 非靜態變量 int j = 1; // 靜態語句塊1 static { m++; i++; // j++; 非靜態變量不能在靜態語句塊中使用 System.out.println("子類靜態初始化塊一 " + "|" + m + "||" + i); } // 靜態語句塊2 static { m++; i++; System.out.println("子類靜態初始化塊二 " + "|" + m + "||" + i); } // 構造函數 public Child() { m++; n++; i++; j++; System.out.println("子類構造方法 " + "|" + m + "|" + n + "|" + i + "|" + j); } // 非靜態語句塊 { m++; n++; i++; j++; System.out.println("子類非靜態初始化塊一" + "|" + m + "|" + n + "|" + i + "|" + j); } // 非靜態語句塊 { m++; n++; i++; j++; System.out.println("子類非靜態初始化塊二" + "|" + m + "|" + n + "|" + i + "|" + j); } // 非靜態方法 public void pMethod() { m++; n++; i++; j++; System.out.println("子類繼承非靜態方法" + "|" + m + "|" + n + "|" + i + "|" + j); return; } // 靜態方法 public static void pStaticMethod() {// 靜態方法不能被繼承 m++; i++; // j++; 非靜態變量不能在靜態方法中使用 return; } // 非靜態方法 public void cMethod() { m++; n++; i++; j++; System.out.println("子類非靜態方法" + "|" + m + "|" + n + "|" + i + "|" + j); return; } // 靜態方法 public static void cStaticMethod() { m++; i++; // j++; 非靜態變量不能在靜態方法中使用 System.out.println("子類靜態方法 " + "|" + m + "||" + i); return; } @Override protected void finalize() throws Throwable { super.finalize(); System.out.println("銷毀子類|"); } }
總結
以上就是本文關于Java中類加載過程全面解析的全部內容,希望對大家有所幫助。如有問題可以隨時留言,小編會及時回復大家的。期待您的寶貴意見。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。