Java類實例化原理


Java對象的創建過程包括 類初始化(JVM類加載機制類實例化兩個階段。

一、Java對象創建時機

(1)使用new關鍵字創建對象

(2)反射創建對象

  使用Class類的newInstance方法

    Student student2 = (Student)Class.forName("Student類全限定名").newInstance();

  使用Constructor類的newInstance方法

    Constructor<Student> constructor = Student.class.getConstructor(Integer.class);

    Student stu3 = constructor.newInstance(123);

 (3)使用Clone方法創建對象(實現Cloneable接口)

  無論何時我們調用一個對象的clone方法,JVM都會幫我們創建一個新的、一樣的對象,特別需要說明的是,用clone方法創建對象的過程中並不會調用任何構造函數。

(4)使用(反)序列化機制創建對象(實現Serializable接口)

  當我們反序列化一個對象時,JVM會給我們創建一個單獨的對象,在此過程中,JVM並不會調用任何構造函數。

二. Java 對象的創建過程

當一個對象被創建時,虛擬機就會為其分配內存來存放對象自己的實例變量及其從父類繼承過來的實例變量(即使這些從超類繼承過來的實例變量有可能被隱藏也會被分配空間)。

在為這些實例變量分配內存的同時,這些實例變量也會被賦予默認值(零值)。

 

主要涉及三種執行對象初始化的結構,分別是 實例變量初始化、實例代碼塊初始化、構造函數初始化

編譯器構造類的構造函數<init>()(按順序執行):

  父類構造器

  實例變量初始化和實例代碼塊初始化相關代碼

  本身構造函數

1、實例變量初始化和實例代碼塊初始化按照編程順序來執行,不允許順序靠前的實例代碼塊訪問其后面定義的實例變量,但是可以賦值。

// 編譯錯誤:代碼塊不可以訪問其后定義的實例變量
public class InstanceInitializer {  
    {  
        j = i;  
    }  

    private int i = 1;  
    private int j;  
}  

// 沒問題:代碼塊可以賦值其后定義的實例變量
public class InstanceInitializer {  
    {  
        j = 1;  
    }  

    private int i = 1;  
    private int j;  
}  

2、每一個Java中的對象都至少會有一個構造函數,如果我們沒有顯式定義構造函數,那么它將會有一個默認無參的構造函數。

  Java強制要求所有對象(Object是Java的頂層對象,沒有超類)構造函數的第一條語句必須是超類構造函數的調用語句或者是類中定義的其他的構造函數(super()/this()必須在第一句,且不能同時出現)。如果我們既沒有調用其他的構造函數,也沒有顯式調用超類的構造函數,那么編譯器會為我們自動生成一個對超類構造函數的調用

3、實例化一個類的對象的過程是一個典型的遞歸過程。

  首先實例化Object類,再依次對以下各類進行實例化,直到完成對目標類的實例化。

三、綜合實例

// 父類
class Foo {
    int i = 1;

    Foo() {
        System.out.println(i);// -----------(1)
        int x = getValue();
        System.out.println(x);// -----------(2)
    }

    {
        i = 2;
    }

    protected int getValue() {
        return i;
    }
}

// 子類
class Bar extends Foo {
    int j = 1;

    Bar() {
        j = 2;
    }

    {
        j = 3;
    }

    @Override
    protected int getValue() {
        return j;
    }
}

public class ConstructorExample {
    public static void main(String... args) {
        Bar bar = new Bar();
        System.out.println(bar.getValue());// -----------(3)
    }
}

/*
 * Output: 2 0 2
 */

//Foo類構造函數的等價變換:
Foo() {
    i = 1;
    i = 2;
    System.out.println(i);
    int x = getValue();// 在執行Foo的構造函數的過程中,由於Bar重載了Foo中的getValue方法,所以其調用的是Bar的getValue方法
    System.out.println(x);
}

//Bar類構造函數的等價變換
Bar() {
    Foo();
    j = 1;
    j = 3;
    j = 2
}

 

 

參考資料:

深入理解Java對象的創建過程:類的初始化與實例化


免責聲明!

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



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