初始化和清理
1、區別方法重載和重寫:
重載:方法名稱一致,通過參數列表區別不同的方法; 發生於本類或者父類、子類;
重寫:方法返回值,方法名, 參數列表必須一致;發生於父類、子類
方法重載時調用的類型轉換:
package com.zifuchuan; public class MyTe8 { public static void main(String[] args) { byte a=6; short b=7; int c=7; long d=7; float e=1.1f; double f=1.2d; test(a); test(b); test(c); test(d); test(e); test(f); test(1.3); test(‘g‘);//字符類型被提升為int類型 test(89);//常數89被當成int類型 int h=10; test2(h); } public static void test(byte arg) { System.out.println("test(byte arg)"); } public static void test(short arg) { System.out.println("test(short arg)"); }public static void test(int arg) { System.out.println("test(int arg)"); } public static void test(long arg) { System.out.println("test1(long arg)"); } public static void test(float arg) { System.out.println("test(float arg)"); } public static void test(doublearg) { System.out.println("test(double arg)"); } public static void test2(long arg) { System.out.println("test2(long arg)"); } public static void test2(double arg) { System.out.println("test2(double arg)"); } }
可知,類型轉化規則:
- 傳入參數的數據類型(實際參數類型)小於方法中申明的參數類型,實際數據類型會被提升,其中字符類型比較特殊,會被提升為int類型 ;
- 傳入參數的數據類型(實際參數類型)大於方法中申明的參數類型,會報錯,需要強制類型轉化;
- 常數89被當成int類型;
2、對象創建,初始化過程
- 首次調用Dog類的靜態方法(構造器也是靜態方法)/靜態域首次被訪問時候,java解析器查找類路徑定位Dog.class文件。載入Dog.class文件(這將創建一個Class對象),靜態初始化相關的動作都會執行(靜態域、靜態代碼塊按照程序中的順序依次初始化),且在Class對象首次加載的時候執行一次。如果有父類,則先找到父類的class文件並載入,再加載子類。以此類推,最終以從基類一直到導出類的順序,分別載入class文件和當前類的靜態初始化,
- 當調用構造器創建Dog對象時候,先在堆上為Dog對象分配存儲空間,並清零(也就將對象的域設置成了默認值,比如引用置為null)。如果有基類,繼續為基類的對象分配存儲空間並清零(導出類的構造器默認調用基類的構造器)。以此類推,最終從導出類到基類的順序分配空間並清零。最頂層的基類對象分配存儲空間並清零後,會執行本類域處的初始化操作,然後執行本類構造器。
- 基類構造器完成後,導出類依次執行所有在字段處和非靜態代碼塊的初始化動作。以此類推,最終從基類到導出類的順序初始化。
- 執行導出類構造器其余部分。
示例:
package com.zifuchuan; public class Beetle extends Insect{ Beetle(){ System.out.println("Beetle構造器初始化"); }
static { System.out.println("Beetle靜態代碼塊1"); } private static int x2=print("x2"); static { System.out.println("Beetle靜態代碼塊2"); } public static void main(String[] args) { System.out.println("main函數執行"); Beetle beetle=new Beetle(); } } class Insect{ { System.out.println("Insect非靜態代碼塊1"); } private int first=print2("Insect非靜態域"); Insect(){ System.out.println("Insect構造器初始化"); } private static int x=print("x"); { System.out.println("Insect非靜態代碼塊2"); } public int print2(String str){ System.out.println(str); return 47; } public static int print(String str){ System.out.println(str); return 47; } }
輸出結果:
x
Beetle靜態代碼塊1
x2
Beetle靜態代碼塊2
main函數執行
Insect非靜態代碼塊1
Insect非靜態域
Insect非靜態代碼塊2
Insect構造器初始化
Beetle構造器初始化
3、垃圾回收器如何工作
- 引用計數--java虛擬機從未采用的垃圾回收技術
引用計數的思想?
每一個對象都含有一個引用計數器,當有新的引用連接至對象時候,引用計數加1;引用置空時候,引用計數減1。垃圾回收器在包含所有對象的列表上遍歷,發現某個對象的引用計數器為0時,就是釋放對象占用的資源。
缺陷:存在循環引用,可能出現本來應該被回收的對象,由於引用計數不為0無法被回收的情況
如何解決“引用計數”的缺陷?
對於一切存活的對象,一定能夠最終追溯到其存活在堆棧或靜態存儲區中的引用,這個引用可能會穿過數個對象層次。基於此前提,從堆棧或靜態存儲區開始遍歷所有的引用就能找到存活的對象。這解決了“引用計數”的缺陷。以下“停止-復制”、”標記-清掃”基於該思想。
- 停止-復制
先暫停程序,然後將所有存活的對象從當前堆復制到另一個堆,沒有被復制的是垃圾,被回收;對象被復制到新堆後是整齊排列的。
缺陷:
需要兩個分離的堆來回復制;如果產生少量垃圾(不存活對象很少),甚至沒有垃圾,垃圾回收器還是會將所有內存從一處復制另一處的堆,很浪費。
- 標記-清掃
不暫停程序,找到存活對象設置一個標記,當全部標記工作完成時候,暫停程序並清理未被標記的垃圾;剩下的堆空間不是整齊排列的。解決了“停止-復制”的缺陷。
JVM虛擬機會跟蹤“停止-復制”的效果,如果對象很穩定,垃圾回收效率低,會切換到“標記-清掃”方式;JVM虛擬機會跟蹤“標記-清掃”的效果,如果堆空間出現很多碎片,會切換回“停止-復制”的方式。這種方式工作方式通常稱為“自適應”技術
初始化和清理