Java中Record類型是Java 14中的預覽函數引入的,並且應作為普通的 不可變 數據類,用於在類和應用程序之間進行數據傳輸。
像Enum 一樣,Record也是一個特殊的類輸入Java。它旨在用於僅創建類以充當普通數據載體的地方。
類(Class)與記錄(Record)之間的重要區別是,Record旨在消除設置和從實例獲取數據所需的所有代碼,Record將這種責任轉移給生成編譯器。
我們可以在 record 定義中覆蓋上面提供的任何默認方法,以實現自定義行為。
Record語法
使用關鍵字 record 在Java中創建此類Record類。就像我們在構造函數中所做的一樣,我們需要在Record中提及屬性及其類型。
在給定的示例中, EmployeeRecord 用於保存員工信息,即
package com.howtodoinjava.core.basic;
public record EmployeeRecord(Long id,
String firstName,
String lastName,
String email,
int age) {
}
Record使用
要創建一條Record,請調用其構造函數並在其中傳遞所有字段信息。然后,我們可以使用JVM生成的getter方法獲取記錄信息,並調用任何生成的方法。
package com.howtodoinjava.core.basic;
public class RecordExample {
public static void main(String[] args)
{
EmployeeRecord e1 = new EmployeeRecord
(1l, "Lokesh", "Gupta", "howtodoinjava@gmail.com", 38);
System.out.println(e1.id());
System.out.println(e1.email());
System.out.println(e1);
}
}
程序輸出:
1 howtodoinjava@gmail.com EmployeeRecord[id=1, firstName=Lokesh, lastName=Gupta, email=howtodoinjava@gmail.com, age=38]
Record查看
當我們創建 EmployeeRecord時,編譯器會創建字節碼,並在生成的類文件中包含以下內容:
- 接受所有字段的構造函數。
toString()方法,用於打印Record中所有字段的狀態/值。- 使用基於
invokedynamic的機制的equals()和hashCode()方法。 - 其名稱類似於字段名稱的getter方法,即
id(),firstName(),lastName(),email()和age()。 - 類
擴展了java.lang.Record,它是所有Record的基類。這意味着Record不能擴展其他類。 - 該類被標記為
final,這意味着我們無法創建它的子類。 - 它沒有任何setter方法,這意味着Record實例被設計為不可變的。
如果在生成的類文件上運行 javap 工具,我們將看到該類文件。
public final class com.howtodoinjava.core.basic.EmployeeRecord extends java.lang.Record {
//1
public com.howtodoinjava.core.basic
.EmployeeRecord(java.lang.Long, java.lang.String, java.lang.String, java.lang.String, int);
//2
public java.lang.String toString();
//3
public final int hashCode();
public final boolean equals(java.lang.Object);
//4
public java.lang.Long id();
public java.lang.String firstName();
public java.lang.String lastName();
public java.lang.String email();
public int age();
}
Record不能被繼承
盡管所有Record都擴展了 java.lang.Record 類,但是我們仍然不能顯式創建 java.lang.Record 的子類。編譯器不會通過。
final class Data extends Record {
private final int unit;
}
// Compiler error : The type Data may not subclass Record explicitly
這意味着獲取Record的唯一方法是顯式聲明一個Record並讓 javac 創建類文件。
Record添加注釋
我們可以為Record的組件添加注釋,這些注釋適用於它們。例如,我們可以將 @Transient 批注應用於 id 字段。
public record EmployeeRecord(
@Transient Long id,
String firstName,
String lastName,
String email,
int age)
{
//
}
Record序列
Record類的 serialVersionUID 是 0L ,除非它是明確聲明。
Record對象序列化的過程無法自定義;Record類定義的任何特定於類的代碼 writeObject,readObject,readObjectNoData,readResolve,writeExternal和readExternal方法在序列化和反序列化期間都將被忽略。但是,writeReplace方法可用於返回要序列化的替代對象。
在執行任何 序列化或反序列化之前,我們必須確保Record必須可序列化或可外部化。
import java.io.Serializable;
public record EmployeeRecord (
Long id,
String firstName,
String lastName,
String email,
int age) implements Serializable
{
}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class RecordExample {
public static void main(String[] args)
{
EmployeeRecord e1 = new EmployeeRecord
(1l, "Lokesh", "Gupta", "howtodoinjava@gmail.com", 38);
writeToFile(e1, "employee1");
System.out.println(readFromFile("employee1"));
}
static void writeToFile(EmployeeRecord obj, String path) {
try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(path))){
oos.writeObject(obj);
} catch (IOException e) {
e.printStackTrace();
}
}
static EmployeeRecord readFromFile(String path) {
EmployeeRecord result = null;
try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path))){
result = (EmployeeRecord) ois.readObject();
} catch (ClassNotFoundException | IOException e) {
e.printStackTrace();
}
return result;
}
}
程序輸出:
EmployeeRecord[id=1, firstName=Lokesh, lastName=Gupta, email=howtodoinjava@gmail.com, age=38]
Record字段和方法
添加到Record中的新字段必須為Static 靜態 也可以添加一種方法,該方法可以訪問Record字段的內部狀態。
編譯器不會在隱式生成的字節碼中使用添加的字段和方法,因此它們不屬於任何方法實現,例如 equals(), hashCode()或 toString()。我們必須根據需要明確使用它們。
public record EmployeeRecord(
Long id,
String firstName,
String lastName,
String email,
int age) implements Serializable
{
//additional field
static boolean minor;
//additional method
public String fullName()
{
return firstName + " " + lastName;
}
}
Record構造函數
我們可以添加構造器特定代碼,以在緊湊的構造器中進行數據驗證。
我們不需要為字段指定構造函數參數的分配,因為它以通常的方式在規范構造函數中發生。
public record EmployeeRecord(
Long id,
String firstName,
String lastName,
String email,
int age) implements Serializable
{
public EmployeeRecord
{
if(age < 18)
{
throw new IllegalArgumentException(
"You cannot hire a minor person as employee");
}
}
}
來源:https://www.learnfk.com/article-java14-java-14-record-type
