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

Java 五種建立物件的方式深度解析

     編輯:Java 相關知識

前言

身為 Java 開發者,我們每天都在建立大量物件,多半仰賴 Spring 等框架管理。但 Java 其實提供了五種根本的物件建立方式,理解它們有助於掌握 JVM 底層機制,也能在面試與框架原理分析中脫穎而出。

五大建立物件方式

1. new 關鍵字

最常見、最直接的方式,可呼叫任意建構子。

Employee emp1 = new Employee();

位元碼指令:new + invokespecial(呼叫建構子)。

2. Class.newInstance()

透過反射呼叫無參建構子。Java 9 後標記為過時,建議改用 Constructor.newInstance()。

Employee emp2 = Employee.class.newInstance();
// 或
Employee emp2 = (Employee) Class.forName("pkg.Employee").newInstance();

位元碼:invokevirtual 呼叫 Class.newInstance()。

3. Constructor.newInstance()

反射 API 的核心,支援帶參建構子,也是 Spring、Hibernate 等框架的首選實例化方式。

Constructor<Employee> constructor = Employee.class.getConstructor();
Employee emp3 = constructor.newInstance();

位元碼:invokevirtual 呼叫 Constructor.newInstance()。

4. clone() 方法

淺層複製現有物件,不呼叫任何建構子。類別需實作 Cloneable 介面並覆寫 clone()。

Employee emp4 = (Employee) emp3.clone();

位元碼:invokevirtual 呼叫 clone()。

5. 反序列化

從位元組流重建物件,同樣不經建構子。類別需實作 Serializable 介面。

ObjectInputStream in = new ObjectInputStream(new FileInputStream("data.obj"));
Employee emp5 = (Employee) in.readObject();

位元碼:invokevirtual 呼叫 ObjectInputStream.readObject()。

位元碼層面的差異

只有 new 指令會轉換為 new + invokespecial;其餘四種皆為 invokevirtual 動態派發。這也是為何框架偏好反射實例化的原因——統一了物件創建入口,便於攔截與增強(如 AOP 代理、依賴注入)。

完整範例程式碼

class Employee implements Cloneable, Serializable {
    private String name;
    public Employee() { System.out.println("Employee Constructor Called..."); }
    // getter/setter、equals、hashCode、toString、clone 略
}

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.newInstance(); emp2.setName("Rishi");
        // 3. Constructor.newInstance()
        Constructor<Employee> c = Employee.class.getConstructor();
        Employee emp3 = c.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...  // new
Employee [name=Naresh], hashcode: -1968815046
Employee Constructor Called...  // Class.newInstance()
Employee [name=Rishi], hashcode: 78970652
Employee Constructor Called...  // Constructor.newInstance()
Employee [name=Yogesh], hashcode: -1641292792
Employee [name=Atul], hashcode: 2051657          // clone:未呼叫建構子
Employee [name=Akash], hashcode: 63313419        // 反序列化:未呼叫建構子

注意:clone 與反序列化不會觸發建構子,這在某些初始化邏輯(如 final 欄位賦值、註冊監聽器)中需特別留意。

總結

方式是否呼叫建構子適用場景
new是日常開發、明確型別
Class.newInstance()是(無參)舊版反射、簡單實例化
Constructor.newInstance()是(可帶參)框架開發、動態載入
clone()否原型模式、效能敏感複製
反序列化否持久化、跨 JVM 傳遞
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved