Java類和對象初始化


類的生命周期:

Java類的初始化:

本階段負責為類變量賦正確的初始值。(類變量即靜態變量)

Java編譯器把所有的類變量初始化語句和靜態初始化器通通收集到<clinit>方法中,該方法只能被JVM調用,專門承擔初始化工作。

初始化一個類必須保證其直接超類已被初始化。

並非所有類都擁有<clinit>()方法。以下類不會擁有<clinit>方法:

  1. 該類既沒有聲明任何類變量,也沒有靜態初始化語句。
  2. 該類聲明了類變量,但沒有使用類變量初始化語句或靜態初始化語句初始化。
  3. 該類只包含靜態final變量的類變量初始化語句,並且類變量初始化語句是常量表達式。

Java類初始化的時機:

規范定義類的初始化時機為“initialize on first active use”,即“在首次主動使用時初始化”。裝載和鏈接在初始化之前就要完成。

首次主動使用的情形:

  1. 創建類的新實例--new,反射,克隆或反序列化;
  2. 調用類的靜態方法;
  3. 操作類和接口的靜態字段;(final字段除外)
  4. 調用Java的特定的反射方法;
  5. 初始化一個類的子類;
  6. 指定一個類作為Java虛擬機啟動時的初始化類(含有main方法的啟動類)。

除了以上6種情形,java中類的其他使用方式都是被動使用,不會導致類的初始化。

Java對象初始化:

編譯器為每個類生成至少一個實例初始化方法,即<init>()方法。此方法與源程序里的每個構造方法對應。如果類沒有聲明構造方法,則生成一個默認構造方法,該方法僅調用父類的默認構造方法,同時生成與該默認構造方法對應的<init>()方法。

<init>()方法內容大概為:

  1. 調用另一個<init>()方法(本類的另外一個<init>()方法或父類的<init>()方法);
  2. 初始化實例變量;
  3. 與其對應的構造方法內的字節碼

Java對象初始化的時機:

對象初始化又稱為對象實例化。Java對象在其被創建時初始化。有兩種方式創建Java對象:

一種是顯示對象創建,通過new關鍵字來調用一個類的構造函數,通過構造函數創建一個對象。

一種是隱式對象創建:

  1. 加載一個包含String字面量的類或接口會引起一個新的String對象創建,除非包含相同字面量的String對象已經在JVM中存在了。
    String s1 = "zheng";

     

  2. 自動裝箱機制可能會引起一個原子類型的包裝類對象被創建。
    Integer iWrapper = 1;

     

  3. String連接符也可能會引起新的String或者StringBuilder對象被創建,同時還有可能引起原子類型的包裝對象被創建。
    System.out.println("zheng"+1);

對象實例初始化的例子:

public class Base
{
    Base() {
        preProcess();
    }
 
    void preProcess() {}
}
public class Derived extends Base
{
    public String whenAmISet = "set when declared";
 
    @Override void preProcess()
    {
        whenAmISet = "set in preProcess()";
    }
}
public class Main
{
    public static void main(String[] args)
    {
        Derived d = new Derived();
        System.out.println( d.whenAmISet );
    }
}

下面是整個的運行流程:

  1. 進入Derived類構造函數
  2. Derived成員變量的內存被分配
  3. 調用Base類的構造函數
  4. Base類構造函數調用preProcess()方法
  5. Derived類的preProcess()方法設置whenAmISet
  6. Derived類的成員變量初始化被調用
  7. 執行Derived構造函數體

可以看到在執行完父類的構造函數后,第6步才對Derived類的成員變量初始化。

Java類初始化例子:

import java.util.Map;
import java.util.HashMap;
import java.util.Collections;
public class Singleton {
    public    static Singleton singleton = new Singleton();
    public static Map m;
    static{
        m = new HashMap();
    }
    private Singleton(){
        initM();
    }
    public static void initM(){
        if(null == m){
            System.out.println("m 為空");
            m = new HashMap();
        }
        m.put("1", "鄭");
        m.put("2", "陳");
    }
    public static Singleton getInstance(){
        return singleton;
    }
}
public class Main {
    public static void main(String [] args){
        Singleton singleton = Singleton.getInstance();
    }
}

運行結果輸出m 為空

是因為在類初始化階段先對singleton賦值調用Singleton類構造函數,然后Singleton類構造函數調用initM()方法。但是此時還沒有運行static方法,所以m=null.

參考博客:

Java構造時成員初始化的陷阱

Java類與對象的初始化

java對象創建過程/初始化順序

解析 Java 類和對象的初始化過程

Java對象初始化詳解

Java單例模式詳解

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM