欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 記錄類Record詳解

 更新時(shí)間:2025年09月22日 09:54:14   作者:探索java  
文章介紹了Java記錄類的引入背景、語(yǔ)法特點(diǎn)及優(yōu)勢(shì),包括自動(dòng)生成構(gòu)造器、訪問(wèn)器、equals、hashCode、toString等方法,強(qiáng)調(diào)其不可變性與類型安全性,適合用于數(shù)據(jù)封裝,并通過(guò)示例和注意事項(xiàng)說(shuō)明其使用場(chǎng)景與局限,感興趣的朋友跟隨小編一起看看吧

引言

在傳統(tǒng) Java 開(kāi)發(fā)中,創(chuàng)建一個(gè)純粹用于封裝數(shù)據(jù)的類(如 DTO 或值對(duì)象)往往需要編寫大量樣板代碼,包括構(gòu)造器、getter、equals、hashCode 和 toString 方法。這些代碼雖然重復(fù),卻難以避免,不僅影響開(kāi)發(fā)效率,也降低了代碼可讀性。

為了解決這一問(wèn)題,Java 在 JEP 359 中提出了“記錄類”這一語(yǔ)言特性,并于 Java 14 首次以預(yù)覽形式引入,在 Java 16 中正式發(fā)布。記錄類的核心設(shè)計(jì)目標(biāo)是為數(shù)據(jù)攜帶類提供一種簡(jiǎn)潔、可讀性強(qiáng)且類型安全的聲明方式。

本篇文章將帶你深入理解記錄類的原理與使用,掌握其各種高級(jí)特性,并通過(guò)豐富示例、性能對(duì)比和最佳實(shí)踐指導(dǎo),助你在實(shí)際項(xiàng)目中合理使用記錄類,寫出更加優(yōu)雅、現(xiàn)代化的 Java 代碼。

語(yǔ)法與基本用法

記錄類的定義方式非常簡(jiǎn)單,使用 record 關(guān)鍵字聲明,取代了傳統(tǒng)類的冗長(zhǎng)結(jié)構(gòu)?;菊Z(yǔ)法如下:

public record Person(String name, int age) {
}

上述代碼定義了一個(gè) Person 記錄類,包含兩個(gè)組件(component):nameage,它們將被編譯器自動(dòng)提升為私有 final 字段,并生成相應(yīng)的方法(稍后將詳細(xì)介紹)。

與傳統(tǒng)類相比,記錄類具備以下特性:

  • 自動(dòng)生成構(gòu)造器、訪問(wèn)器、equals、hashCode、toString
  • 所有字段默認(rèn) private final。
  • 構(gòu)造器參數(shù)與字段一一對(duì)應(yīng)。
  • 支持接口實(shí)現(xiàn)、泛型和靜態(tài)成員。

示例:基本記錄類定義

public record Book(String title, double price) {
}
public class Main {
    public static void main(String[] args) {
        Book book = new Book("Java 精通之路", 79.9);
        System.out.println(book.title());
        System.out.println(book);
    }
}

輸出結(jié)果:

Java 精通之路
Book[title=Java 精通之路, price=79.9]

自動(dòng)生成方法詳解

記錄類的核心價(jià)值之一是其自動(dòng)生成的標(biāo)準(zhǔn)方法,這不僅減少了開(kāi)發(fā)者的重復(fù)工作,也保證了行為的一致性和語(yǔ)義清晰性。以下是記錄類在編譯階段自動(dòng)生成的方法列表:

  • 所有字段的 訪問(wèn)器方法(accessor)
  • 一個(gè) 規(guī)范構(gòu)造器(canonical constructor)
  • equals(Object obj) 方法
  • hashCode() 方法
  • toString() 方法

1. 訪問(wèn)器方法

每個(gè)組件都會(huì)生成一個(gè)訪問(wèn)器方法,其方法名與字段名一致。例如:

public record User(String username, String role) {
}
User user = new User("alice", "admin");
System.out.println(user.username()); // 輸出:alice
System.out.println(user.role());     // 輸出:admin

注意:記錄類不生成傳統(tǒng)的 getUsername() 形式的方法。

2. equals 和 hashCode 方法

記錄類會(huì)基于字段值自動(dòng)生成合理的 equalshashCode 方法。

User user1 = new User("alice", "admin");
User user2 = new User("alice", "admin");
System.out.println(user1.equals(user2)); // true
System.out.println(user1.hashCode() == user2.hashCode()); // true

比較是基于組件值進(jìn)行的,而非引用。

3. toString 方法

記錄類默認(rèn)實(shí)現(xiàn)了符合邏輯的 toString() 方法,格式為:類名[字段1=值1, 字段2=值2]

System.out.println(user1.toString());
// 輸出:User[username=alice, role=admin]

4. 規(guī)范構(gòu)造器

編譯器會(huì)生成一個(gè)公共構(gòu)造器,其參數(shù)列表與組件順序一致:

public User(String username, String role) {
    this.username = username;
    this.role = role;
}

此構(gòu)造器不能省略字段賦值,且不能繞過(guò)不可變性。

不可變性的特性與價(jià)值

記錄類的一個(gè)顯著特性是:不可變性(Immutability)。一旦創(chuàng)建了記錄類實(shí)例,其狀態(tài)便不可更改,這使得記錄類天然適合用于線程安全的數(shù)據(jù)傳遞、緩存鍵、日志記錄和函數(shù)式編程等場(chǎng)景。

不可變性的實(shí)現(xiàn)方式

在記錄類中:

  • 所有組件字段默認(rèn)是 private final,且不能被修改。
  • 沒(méi)有生成 setter 方法。
  • 構(gòu)造函數(shù)中必須為所有字段賦值,且不能通過(guò)反射等方式繞過(guò)字段 final 的限制(除非使用非法手段)。
public record Customer(String id, String name) {
    // 無(wú)法修改 id 和 name
}
Customer c1 = new Customer("001", "Alice");
c1.name = "Bob"; // 編譯錯(cuò)誤,字段是 final 的

不可變性的優(yōu)勢(shì)

  • 線程安全:多個(gè)線程可安全共享記錄類實(shí)例,而無(wú)需加鎖。
  • 更少的副作用:狀態(tài)不可更改,避免由于共享狀態(tài)帶來(lái)的錯(cuò)誤。
  • 更簡(jiǎn)單的調(diào)試與測(cè)試:數(shù)據(jù)不會(huì)在調(diào)用鏈中被意外修改,提高可預(yù)測(cè)性。
  • 易于緩存和哈希結(jié)構(gòu)使用:不可變對(duì)象可作為 Map 的鍵,不會(huì)影響哈希值。

與傳統(tǒng)類的對(duì)比

在傳統(tǒng) Java 類中,需要人為地將字段設(shè)置為 private final,并避免提供 setter 方法,才能勉強(qiáng)模擬不可變性:

public final class ImmutablePerson {
    private final String name;
    private final int age;
    public ImmutablePerson(String name, int age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public int getAge() {
        return age;
    }
}

記錄類通過(guò)語(yǔ)法層級(jí)的約束,天然支持不可變性,避免了人為失誤。

注意事項(xiàng):深層不可變性

雖然記錄類本身是不可變的,但如果其字段是可變對(duì)象(如 List、Map、數(shù)組),則需要謹(jǐn)慎處理。

public record UserProfile(String username, List<String> tags) {
}
List<String> list = new ArrayList<>();
list.add("java");
UserProfile profile = new UserProfile("bob", list);
profile.tags().add("record"); // 可變字段被修改

上述代碼中,雖然 tags 字段本身是 final,但它引用的是一個(gè)可變列表,因此對(duì)象并不是真正不可變。

解決方案:

  • 在構(gòu)造函數(shù)中進(jìn)行 defensive copy(防御性復(fù)制)。
  • 使用 List.copyOf() 創(chuàng)建不可變集合。
public record SafeUserProfile(String username, List<String> tags) {
    public SafeUserProfile {
        tags = List.copyOf(tags);
    }
}

這樣就能保證 tags 無(wú)法在外部被修改,真正實(shí)現(xiàn)深層不可變。

構(gòu)造器機(jī)制

盡管記錄類自動(dòng)為我們生成了標(biāo)準(zhǔn)構(gòu)造器,但在實(shí)際開(kāi)發(fā)中,仍有很多場(chǎng)景需要我們自定義構(gòu)造邏輯,比如字段校驗(yàn)、數(shù)據(jù)轉(zhuǎn)換等。Java 記錄類支持三種構(gòu)造器形式:

  • 規(guī)范構(gòu)造器(Canonical Constructor)
  • 緊湊構(gòu)造器(Compact Constructor)
  • 自定義構(gòu)造器(Custom Constructor)

規(guī)范構(gòu)造器(Canonical Constructor)

規(guī)范構(gòu)造器是由編譯器自動(dòng)生成的構(gòu)造函數(shù),其參數(shù)列表與組件順序一致,默認(rèn)行為是將所有字段賦值:

public record Product(String name, double price) {
    // 編譯器生成如下構(gòu)造器:
    // public Product(String name, double price) {
    //     this.name = name;
    //     this.price = price;
    // }
}

我們也可以顯式地定義規(guī)范構(gòu)造器,來(lái)加入自定義邏輯,例如參數(shù)校驗(yàn):

public record Product(String name, double price) {
    public Product {
        if (price < 0) {
            throw new IllegalArgumentException("價(jià)格不能為負(fù)數(shù)");
        }
    }
}

緊湊構(gòu)造器(Compact Constructor)

Java 為記錄類提供了一種語(yǔ)法糖,稱為“緊湊構(gòu)造器”。在緊湊構(gòu)造器中,我們無(wú)需列出參數(shù)列表,編譯器會(huì)自動(dòng)將構(gòu)造器參數(shù)與字段綁定。

public record Student(String name, int age) {
    public Student {
        if (age < 0) {
            throw new IllegalArgumentException("年齡不能為負(fù)數(shù)");
        }
    }
}

等價(jià)于:

public record Student(String name, int age) {
    public Student(String name, int age) {
        if (age < 0) {
            throw new IllegalArgumentException("年齡不能為負(fù)數(shù)");
        }
        this.name = name;
        this.age = age;
    }
}

緊湊構(gòu)造器簡(jiǎn)化了字段賦值過(guò)程,適用于多數(shù)校驗(yàn)邏輯場(chǎng)景。

自定義構(gòu)造器與重載

記錄類可以定義額外的構(gòu)造器,但這些構(gòu)造器必須調(diào)用規(guī)范構(gòu)造器,不能繞過(guò)字段賦值流程:

public record Coordinate(int x, int y) {
    public Coordinate() {
        this(0, 0); // 默認(rèn)構(gòu)造
    }
    public Coordinate(int value) {
        this(value, value); // 重載構(gòu)造
    }
}

注意:

  • 所有非規(guī)范構(gòu)造器都必須顯式調(diào)用 this(...)
  • 不能定義不初始化所有字段的構(gòu)造器。

通過(guò)構(gòu)造器機(jī)制,記錄類不僅保持了不可變性,還為開(kāi)發(fā)者提供了足夠的靈活性,用于字段校驗(yàn)、默認(rèn)值填充、工廠構(gòu)造等實(shí)際需求。

高級(jí)特性

記錄類雖然語(yǔ)法簡(jiǎn)潔,但功能并不簡(jiǎn)單。它支持許多高級(jí)語(yǔ)言特性,包括靜態(tài)成員、接口實(shí)現(xiàn)、泛型定義以及本地記錄類的聲明,使其具備在復(fù)雜應(yīng)用中廣泛使用的能力。

靜態(tài)成員

記錄類可以像普通類一樣包含靜態(tài)字段、靜態(tài)方法和靜態(tài)代碼塊,這些靜態(tài)成員的行為與傳統(tǒng)類完全一致。

public record Color(int red, int green, int blue) {
    public static final Color BLACK = new Color(0, 0, 0);
    public static final Color WHITE = new Color(255, 255, 255);
    public static String toHex(Color c) {
        return String.format("#%02x%02x%02x", c.red(), c.green(), c.blue());
    }
}
Color white = Color.WHITE;
System.out.println(Color.toHex(white)); // 輸出:#ffffff

接口實(shí)現(xiàn)

記錄類可以實(shí)現(xiàn)接口(包括函數(shù)式接口),并提供對(duì)應(yīng)方法實(shí)現(xiàn)。

public interface Identifiable {
    String id();
}
public record Employee(String id, String name) implements Identifiable {
    // 自動(dòng)實(shí)現(xiàn) id() 方法
}

記錄類實(shí)現(xiàn)接口時(shí),可以通過(guò)組件直接滿足接口方法簽名,進(jìn)一步提升了類型的表達(dá)力。

泛型支持

記錄類可以定義為泛型類型,從而適用于多種數(shù)據(jù)類型的封裝。

public record Pair<K, V>(K key, V value) {
}
Pair<String, Integer> entry = new Pair<>("age", 30);
System.out.println(entry.key());   // 輸出:age
System.out.println(entry.value()); // 輸出:30

泛型記錄類尤其適用于通用值對(duì)象、鍵值對(duì)封裝、元組等使用場(chǎng)景。

本地記錄類(Local Records)

從 Java 16 開(kāi)始,記錄類也可以在方法內(nèi)部定義,稱為“本地記錄類”,適用于封裝局部方法邏輯中的中間數(shù)據(jù)結(jié)構(gòu)。

public class ReportGenerator {
    public void generate() {
        record Summary(String title, int count) {}
        Summary summary = new Summary("周報(bào)", 12);
        System.out.println(summary);
    }
}

本地記錄類只在方法范圍內(nèi)可見(jiàn),能夠提升臨時(shí)數(shù)據(jù)處理的類型安全性與可讀性,避免引入冗余的外部類定義。

通過(guò)這些高級(jí)特性,記錄類在保持簡(jiǎn)潔的同時(shí),依然具備高度靈活性,能夠應(yīng)對(duì)多種開(kāi)發(fā)需求,適用于從簡(jiǎn)單 DTO 到泛型模型、工具類的廣泛場(chǎng)景。

限制與注意事項(xiàng)

盡管記錄類極大簡(jiǎn)化了不可變數(shù)據(jù)類的開(kāi)發(fā),但其設(shè)計(jì)也存在一些固有的限制,了解這些限制有助于合理使用,避免不合適的場(chǎng)景導(dǎo)致代碼設(shè)計(jì)問(wèn)題。

1. 繼承限制

  • 記錄類隱式繼承自 java.lang.Record,不允許繼承其他類。
  • 記錄類本身是 final 的,不能被繼承。
  • 這意味著無(wú)法通過(guò)繼承擴(kuò)展記錄類行為,只能通過(guò)組合或接口實(shí)現(xiàn)進(jìn)行擴(kuò)展。
// 編譯錯(cuò)誤,記錄類不能繼承其他類 public record MyRecord extends SomeClass { } // 編譯錯(cuò)誤,記錄類不能被繼承 public class SubRecord extends MyRecord { }

2. 字段限制

  • 所有組件字段自動(dòng)為 private final,不能定義非 final 字段。
  • 不支持額外的實(shí)例字段,只能通過(guò)靜態(tài)字段擴(kuò)展類功能。

3. 不支持無(wú)參構(gòu)造器

  • 記錄類必須初始化所有組件字段,不能定義無(wú)參構(gòu)造器。
  • 但可通過(guò)自定義構(gòu)造器為字段賦默認(rèn)值,實(shí)現(xiàn)類似無(wú)參構(gòu)造器的效果。

4. 不支持可變字段

  • 記錄類設(shè)計(jì)為不可變,因此組件字段不能是可變的。
  • 如果字段引用了可變對(duì)象,需自行保證深不可變性(如使用不可變集合或防御性復(fù)制)。

5. 限制擴(kuò)展性

  • 由于不能繼承和添加實(shí)例字段,記錄類不適合表示需要復(fù)雜行為和狀態(tài)管理的實(shí)體。
  • 更適合用于簡(jiǎn)單數(shù)據(jù)載體(如 DTO、值對(duì)象)。

6. 序列化限制

  • 記錄類實(shí)現(xiàn)了 Serializable,但序列化時(shí)遵循組件字段的序列化規(guī)則。
  • 如果字段不可序列化,會(huì)導(dǎo)致序列化失敗。

理解并遵守這些限制,有助于避免誤用記錄類導(dǎo)致設(shè)計(jì)不佳和維護(hù)困難。

到此這篇關(guān)于Java 記錄類Record詳解的文章就介紹到這了,更多相關(guān)Java Record 類內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java中自帶有并發(fā)屬性的List總結(jié)

    java中自帶有并發(fā)屬性的List總結(jié)

    java中有很多l(xiāng)ist,但是原生支持并發(fā)的并不多,那么java中的并發(fā)list到底有哪些呢?下面小編就來(lái)給大家介紹一下ArrayList、CopyOnWriteArrayList、ConcurrentLinkedDeque這幾個(gè)吧
    2023-09-09
  • java 根據(jù)坐標(biāo)截取圖片實(shí)例代碼

    java 根據(jù)坐標(biāo)截取圖片實(shí)例代碼

    這篇文章主要介紹了java 根據(jù)坐標(biāo)截取圖片實(shí)例代碼的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • JDK從8升級(jí)到21的問(wèn)題集(附案例代碼)

    JDK從8升級(jí)到21的問(wèn)題集(附案例代碼)

    JDK 8升級(jí)到JDK 21是一個(gè)重要的版本遷移,涉及語(yǔ)法、模塊化、API變更等多方面調(diào)整,這篇文章主要介紹了JDK從8升級(jí)到21問(wèn)題的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-09-09
  • mybatisPlus 實(shí)體類與數(shù)據(jù)庫(kù)表映射關(guān)系詳解

    mybatisPlus 實(shí)體類與數(shù)據(jù)庫(kù)表映射關(guān)系詳解

    這篇文章主要介紹了mybatisPlus 實(shí)體類與數(shù)據(jù)庫(kù)表映射關(guān)系詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教。
    2022-01-01
  • Java利用MessageFormat實(shí)現(xiàn)短信模板的匹配

    Java利用MessageFormat實(shí)現(xiàn)短信模板的匹配

    這篇文章主要介紹了Java利用MessageFormat實(shí)現(xiàn)短信模板的匹配,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2018-06-06
  • Java?Bean?Validation使用示例詳解

    Java?Bean?Validation使用示例詳解

    這篇文章主要為大家介紹了Java?Bean?Validation的使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-11-11
  • SpringBoot的ConfigurationProperties或Value注解無(wú)效問(wèn)題及解決

    SpringBoot的ConfigurationProperties或Value注解無(wú)效問(wèn)題及解決

    在SpringBoot項(xiàng)目開(kāi)發(fā)中,全局靜態(tài)配置類讀取application.yml或application.properties文件時(shí),可能會(huì)遇到配置值始終為null的問(wèn)題,這通常是因?yàn)樵趧?chuàng)建靜態(tài)屬性后,IDE自動(dòng)生成的Get/Set方法包含了static關(guān)鍵字
    2024-11-11
  • Spring 4.1+JSONP的使用指南

    Spring 4.1+JSONP的使用指南

    在解釋JSONP之前,我們需要了解下”同源策略“,這對(duì)理解跨域有幫助。基于安全的原因,瀏覽器是存在同源策略機(jī)制的,同源策略阻止從一個(gè)源加載的文檔或腳本獲取或設(shè)置另一個(gè)源加載額文檔的屬性。說(shuō)的簡(jiǎn)單點(diǎn)就是瀏覽器限制腳本只能和同協(xié)議、同域名、同端口的腳本進(jìn)行交互。
    2016-04-04
  • Spring Boot和Docker實(shí)現(xiàn)微服務(wù)部署的方法

    Spring Boot和Docker實(shí)現(xiàn)微服務(wù)部署的方法

    這篇文章主要介紹了Spring Boot和Docker實(shí)現(xiàn)微服務(wù)部署的方法,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2019-01-01
  • Java?map和bean互轉(zhuǎn)常用的方法總結(jié)

    Java?map和bean互轉(zhuǎn)常用的方法總結(jié)

    這篇文章主要給大家介紹了關(guān)于Java中map和bean互轉(zhuǎn)常用方法的相關(guān)資料,平時(shí)日常Java開(kāi)發(fā),經(jīng)常會(huì)涉及到Java?Bean和Map之間的類型轉(zhuǎn)換,需要的朋友可以參考下
    2023-09-09

最新評(píng)論