首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> Java 程式設計 >> Java 相關知識

Java 創建對象的 5 種方式全解析:從 new 到反序列化的字節碼視角

     編輯:Java 相關知識

五大創建方式總覽

方式關鍵 API是否調用構造器典型場景
1. new 關鍵字new Class()✅ 是最常用、最直接
2. Class.newInstance()Class.forName(...).newInstance()✅ 是(無參構造器)早期反射、框架舊代碼
3. Constructor.newInstance()clazz.getConstructor().newInstance()✅ 是(可帶參/私有)現代反射、Spring/Hibernate
4. clone()obj.clone()❌ 否原型模式、拷貝對象
5. 反序列化ObjectInputStream.readObject()❌ 否分布式傳輸、持久化恢復

字節碼層面驗證

運行以下測試程序,觀察構造器調用次數:

public class ObjectCreation {
    public static void main(String[] args) throws Exception {
        // 1. new 關鍵字
        Employee emp1 = new Employee();
        emp1.setName("Naresh");

        // 2. Class.newInstance()
        Employee emp2 = (Employee) Class.forName("pkg.Employee").newInstance();
        emp2.setName("Rishi");

        // 3. Constructor.newInstance()
        Constructor<Employee> ctor = Employee.class.getConstructor();
        Employee emp3 = ctor.newInstance();
        emp3.setName("Yogesh");

        // 4. clone()
        Employee emp4 = (Employee) emp3.clone();
        emp4.setName("Atul");

        // 5. 反序列化
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("data.obj"));
        out.writeObject(emp4); out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
        Employee emp5 = (Employee) in.readObject();
        in.close();
        emp5.setName("Akash");
    }
}

輸出結果:

Employee Constructor Called...  // emp1
Employee Constructor Called...  // emp2
Employee Constructor Called...  // emp3
                                // emp4 無輸出
                                // emp5 無輸出

驗證結論:方式 1-3 均調用構造器;方式 4-5 繞過構造器直接在堆上分配內存並拷貝/恢復字段。

核心類定義(支援 clone/序列化)

class Employee implements Cloneable, Serializable {
    private static final long serialVersionUID = 1L;
    private String name;

    public Employee() { System.out.println("Employee Constructor Called..."); }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    @Override public Object clone() {
        try { return super.clone(); }
        catch (CloneNotSupportedException e) { throw new AssertionError(e); }
    }
    // equals/hashCode/toString 略
}

字節碼指令對比

  • new:new + invokespecial(構造器調用)
  • Class.newInstance():invokevirtual → 內部委託 Constructor.newInstance()
  • Constructor.newInstance():invokevirtual(直接反射調用)
  • clone():invokevirtual → JVM 內部 Object.clone() 為 native
  • readObject():invokevirtual → 反序列化引擎直接填充字段

實戰選型建議

  • 日常開發:優先用 new 或依賴注入框架(Spring)管理生命週期。
  • 框架開發/動態載入:Constructor.newInstance(),支援帶參構造器、私有構造器。
  • 高效能拷貝:clone() 需實現 Cloneable,注意淺拷貝陷阱。
  • 跨進程/持久化:序列化/反序列化,需實現 Serializable,注意 serialVersionUID 維護。

理解創建對象的本質差異,有助於排查框架初始化問題、優化高併發場景物件創建、正確實現拷貝與序列化邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved