1. 程式人生 > >初始化和清理

初始化和清理

println 效率 循環 st2 ring 加載 應該 string 示例

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(double
arg) { 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虛擬機會跟蹤“標記-清掃”的效果,如果堆空間出現很多碎片,會切換回“停止-復制”的方式。這種方式工作方式通常稱為“自適應”技術

初始化和清理