JPA 實體中需要默認構造函數
一、概述
在本快速教程中,我們將了解 JPA 對實體類中默認無參數構造函數的要求。
為了理解無參數構造函數的重要性,我們將使用Employee
實體的一個簡單示例。我們將觀察缺少默認構造函數是如何導致編譯時錯誤的。我們將深入研究 JPA 對 Reflection 的使用以進行實體實例化。此外,我們將簡要介紹為什麼在這些類中可能需要此構造函數的其他一些原因。
2. 示例設置
讓我們設置一個名為Employee
的實體類的簡單示例,其中包含名稱、部門和自動生成的 ID。讓我們定義一個包含所有三個字段的構造函數:
@Entity
public class Employee {
@Id
private Long id;
private String name;
private int age;
public Employee(Long id, String name, int age) {
this.id = id;
this.name = name;
this.age = age;
}
// getters and setters
}
然而,在這一點上,我們會注意到Employee
類不會編譯:
很明顯,在這裡我們可以看到我們已經定義了一個帶有參數化構造函數的Entity
類,但是沒有無參數構造函數。在這種情況下,存在**一個編譯時錯誤,表明除了現有構造函數之外,我們還需要一個無參數構造函數。**
在接下來的兩節中,我們將了解圍繞Entity
類中的構造函數的 JPA 規範。我們將了解如何修復錯誤以及 JPA 強加這些約束的根本原因。
3. JPA 規範、構造函數和反射
JPA 規範要求所有Entity
類都具有默認的無參數構造函數。這可以是public
或protected
。
如果沒有定義其他構造函數,將在編譯時自動提供一個默認的無參數構造函數。但是,如果我們定義了參數化構造函數,我們還必須顯式提供默認構造函數。
JPA 使用此默認構造函數來使用 Reflection 創建實體類的實例。它提供了一種動態創建類實例、調用方法和訪問字段的方法。
要使用反射創建類的實例,我們可以使用Class
類及其newInstance()
方法。當 JPA 創建持久實體類的實例時,它首先使用實體的完全限定類名獲取其Class
對象。一旦擁有Class
對象,JPA 就會使用 Reflection 通過調用無參數構造函數來創建該類的新實例。因此,在 JPA 實體類中提供無參數構造函數始終是一個好習慣,即使我們沒有顯式使用它也是如此。
簡單地說,為了解決這個問題,讓我們在Employee
實體類中顯式定義一個無參數構造函數:
@Entity
public class Employee implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
private String dept;
private int salary;
public Employee(String name, String dept, int salary) {
this.name = name;
this.dept = dept;
this.salary = salary;
}
public Employee() {
}
}
現在編譯時錯誤已修復:
顯然,現在通過引入無參構造函數解決了之前的編譯器錯誤。
4. 無參數構造函數的原因
首先,正如我們在上一節中簡要討論的那樣,Hibernate 等 JPA 實現使用反射來創建實體類的實例。這允許在運行時進行動態類檢查和實例化。要創建實體對象,JPA 提供者需要調用不帶任何參數的構造函數。如果不存在無參數構造函數,則會在對象實例化期間導致異常。
此外, JPA 提供者經常使用代理對象來優化性能和延遲加載關係。代理對像是動態生成的實體類的子類。這些子類需要一個無參數的構造函數來創建實例並實現它們的目的。沒有它,代理機制就會失敗,導致運行時錯誤。
最後,我們知道 JPA 提供實體和數據庫表之間的雙向映射。在將實體對象映射到它們對應的數據庫記錄的過程中,JPA 提供者必須創建實體類的實例。如果沒有無參數構造函數,提供者將無法實例化實體對象,從而導致映射失敗和數據檢索問題。
5.結論
在本文中,我們討論了實體類中對默認無參數構造函數的需求。
我們了解到,它使 JPA 提供程序能夠實例化對象、利用代理機制以及在實體和數據庫表之間執行無縫映射。
缺少無參數構造函數會導致編譯時錯誤,從而阻止持久性操作的成功執行。通過了解對無參數構造函數的需求以及反射在處理實體實例化中的作用,我們可以確保基於 JPA 的應用程序的順利運行。