Java 中的记录与类

java 中的记录与类

如果您已经了解 java 中的记录,您可能会发现它的用法与类非常相似,但必须考虑到一些重要的差异。在本文中,我们将了解 java 中记录之间的差异。如果您仍然不知道记录,我建议阅读我的文章《java 中的记录:它们是什么以及如何使用它们》。

不变性

不可变对象是指一旦创建对象,其属性就无法修改的对象。对于 records 来说,它们是不可变的,也就是说,一旦创建 record 类型的对象,其属性就无法修改。另一方面,类可能是不变的,也可能不是不变的,具体取决于它的实现方式。这部分确保数据的完整性并防止其被意外修改。

目的

类通常只是为了存储数据而编写,例如来自数据库查询的数据或来自表单的数据。在许多情况下,该数据是不可变的,因为需要在不使用同步的情况下确保数据的有效性。为了实现这一点,使用以下元素编写一个类:

每个字段的私有属性。每个字段的获取器。初始化所有字段的构造函数。比较对象是否相等的 equals 方法。hashcode 方法,根据字段生成哈希码。一个 tostring 方法,用于生成字段的字符串表示形式。

例如,如果你有一个 person 类,有两个属性 name 和 lastname,你可以这样写:

public class person {    private final string name;    private final string lastname;    public person(string name, string lastname) {        this.name = name;        this.lastname = lastname;    }    public string getname() {        return name;    }    public string getlastname() {        return lastname;    }    @override    public string tostring() {        return "person{" + "name='" + name + ''' +                ", lastname='" + lastname + ''' +                '}';    }    @override    public boolean equals(object o) {        if (this == o) return true;        if (!(o instanceof person person)) return false;        return objects.equals(getname(), person.getname()) && objects.equals(getlastname(), person.getlastname());    }    @override    public int hashcode() {        return objects.hash(getname(), getlastname());    }}

这是该任务的解决方案,但它是实际需要的大量代码。如果类具有更多属性,即使在 ide 或 github copilot 等插件的帮助下完成,编写的代码也会更长。更好的解决方案是将我们的类声明为数据类,即仅存储数据的类,并且不必具有特定行为,这就是 records 的用武之地。

立即学习“Java免费学习笔记(深入)”;

这样,person 类就可以重写为记录,如下所示:

Ai好记 Ai好记

强大的AI音视频转录与总结工具

Ai好记 311 查看详情 Ai好记

public record person(string name, string lastname) { }

这会自动生成 equals、hashcode 和 tostring 方法,以及每个属性的 getter 方法。

记录和类之间有什么区别

不可变性记录是不可变的,也就是说,记录类型的对象一旦创建,其属性就无法修改。相反,类可能是不变的,也可能不是不变的,具体取决于它的实现方式。生成方法记录自动生成equals、hashcode和tostring方法,以及每个属性的getter方法。另一方面,在类中,这些方法必须手动实现或借助 ide 实现。在oop中使用记录不能从其他类继承,也不能被其他类扩展,但它们可以实现接口。另一方面,类可以从其他类继承、扩展,并且通常非常适合涵盖面向对象编程的概念。语法记录的语法比类更简单,因为它可以在一行中定义,而类需要多行代码。用途记录是一种类似于dto(数据传输对象)的结构,即帮助建模不可变数据的类,其一部分是 是一个更通用的结构,可以有行为和状态。

何时使用记录,何时使用类?

如果需要的是一个不可变的数据结构来存储数据,并且不需要对属性进行任何修改(简单地看成是一个承载信息的对象)。另一方面,如果您需要具有独特逻辑和特定方法的更通用的结构、面向对象范例的方法、应用设计模式或使用 jpa 或 hibernate 等,那么您应该使用类。

额外:具有可变属性的记录

让我们考虑以下示例,有两条记录 product,其属性为名称和价格,还有一个 cart,其具有 arraylist 类型的单个属性 products 以及一些获取产品数量和购物车总数的方法。

package org.jordi.example;public record product(string name, double price) { }
package org.jordi.example;import java.util.arraylist;import java.util.list;public record cart(list products) {    public cart() {        this(new arraylist());    }    public int getquantity() {        return this.products.size();    }    public double gettotal() {        return this.products.stream().maptodouble(product::price).sum();    }}

本例中的问题是,每个 记录 本身都是不可变的,但在记录 cart 的情况下,具有 arraylist 类型的属性,并且由于 arraylist 本质上是可变的,一旦记录购物车实例化,就可以修改列表的内容。

package org.jordi.example;public class Main {    public static void main(String[] args) {        Product water = new Product("Water", 15);        Product milk = new Product("Milk", 22);        Cart cart = new Cart();        cart.products().add(water);        cart.products().add(milk);        System.out.println("Price: " + cart.getTotal());        cart.products().clear();        System.out.println("Quantity: " + cart.getQuantity());        System.out.println("Price: " + cart.getTotal());    }}

上面的代码编译没有问题,因为只修改了列表的内容,但产品属性本身没有被修改。这只是特定情况的示例,可能没有必要,但很高兴知道这是可以做到的。

以上就是Java 中的记录与类的详细内容,更多请关注创想鸟其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 chuangxiangniao@163.com 举报,一经查实,本站将立刻删除。
发布者:程序猿,转转请注明出处:https://www.chuangxiangniao.com/p/452599.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2025年11月8日 00:00:42
下一篇 2025年11月8日 00:04:35

相关推荐

  • Go语言中高效获取与解析HTML/XML内容的指南

    本教程详细介绍了在go语言中如何高效地获取网页html/xml内容,并提供了相应的解析方法。我们将使用go标准库中的`net/http`包来发送http请求和读取响应,并探讨`encoding/xml`包进行xml解析,以及`golang.org/x/net/html`包进行html解析。文章将通过…

    2025年12月16日
    000
  • Go 命名返回值与 flag 包的变量声明机制解析

    本文深入探讨 go 语言中命名返回值的工作机制,解释为何在函数签名中声明的命名返回值可以直接用于 `flag.intvar` 等函数,而无需额外使用 `var` 关键字进行显式声明。我们将通过示例代码对比分析,明确命名返回值在函数入口处自动初始化为零值的特性,以及其与未声明变量导致编译错误的根本区别…

    2025年12月16日
    000
  • 如何使用Golang编写DevOps自动化脚本

    答案:Go语言凭借高并发、编译型性能和跨平台优势,适合编写稳定高效的DevOps自动化脚本。1. 使用os/exec包执行系统命令并封装复用,实时输出日志;2. 利用os、io/ioutil等标准库处理文件与配置,支持YAML解析和模板渲染;3. 通过net/http调用API,可封装Client实…

    2025年12月16日
    000
  • Go语言多返回值:底层实现与工作原理

    go语言的多返回值机制并非简单地返回一个元组或数组,而是在底层通过将返回值直接放置到调用栈上或寄存器中实现。调用方随后从这些位置检索数据,这种直接的内存或寄存器操作方式,确保了高效的数据传递,与c语言处理单个返回值的方式有异曲同工之妙,但go扩展了其功能以支持多个返回值。 Go语言多返回值机制概述 …

    2025年12月16日
    000
  • Revel框架中获取特定模块的所有国际化字符串

    本文探讨了在Revel框架中批量获取特定模块和语言的所有国际化字符串的挑战与解决方案。鉴于Revel默认的国际化机制是基于消息(即需要原始字符串才能获取翻译),直接访问所有翻译键值对并不直接。文章提出了通过自定义函数、向Revel贡献代码或采用本地代码复制等多种方法来绕过这一限制,并提供了实现思路和…

    2025年12月16日
    000
  • Go语言中“声明但未使用”错误的深度解析与解决方案

    本文深入探讨了go语言中常见的“声明但未使用”编译错误,特别是在循环中使用短变量声明符`:=`时引发的变量遮蔽问题。我们将通过示例代码详细解释其发生机制,并提供使用赋值操作符`=`等多种解决方案及最佳实践,帮助开发者避免此类错误,提升代码质量和可读性。 理解Go语言的变量声明与作用域 在Go语言中,…

    2025年12月16日
    000
  • Go语言中Haml/Slim风格模板的探索与实践

    本文旨在探讨go语言生态中haml或slim风格模板引擎的可用性,为那些习惯于简洁、缩进式模板语法的开发者提供替代方案。我们将介绍社区中已有的go语言haml解析器项目,并讨论其基本用法、集成考量及选择第三方模板引擎时需要注意的事项,帮助开发者在go项目中实现更高效的视图层开发。 Go语言模板引擎的…

    2025年12月16日
    000
  • Go程序静态链接GNU Readline库:Cgo集成与注意事项

    本文详细阐述了如何在go项目中静态链接gnu readline库,以简化部署并避免动态链接问题。核心方法包括将readline的c语言源代码嵌入go项目,并通过cgo的cflags和ldflags指令集成编译。文章还讨论了go语言的替代方案以及gpl许可证的潜在影响,为开发者提供了全面的实践指南。 …

    2025年12月16日
    000
  • 如何在Golang中配置环境变量

    配置Go环境需设置GOROOT、GOPATH、GOBIN和PATH,Linux/macOS通过shell配置,Windows通过系统设置或PowerShell;在代码中使用os.Getenv读取变量,配合godotenv库可从.env文件加载配置,提升项目安全与可维护性。 在Golang中配置环境变…

    2025年12月16日
    000
  • Go 语言中利用 reflect 包动态创建指定类型切片

    本教程详细阐述了如何在 Go 语言中使用 `reflect` 包动态创建指定类型的切片。通过 `reflect.SliceOf` 获取切片类型,并结合 `reflect.MakeSlice` 实现切片的实例化,同时探讨了创建零值切片或空切片的两种方法,并提供示例代码和使用场景建议。 引言:动态切片创…

    2025年12月16日
    000
  • Go语言中变量声明与短变量声明的陷阱:作用域与变量遮蔽

    本文深入探讨go语言中`var`关键字声明与`:=`短变量声明的区别,特别是它们在不同作用域内可能导致的变量遮蔽问题。通过具体示例,解释了为何编译器会报告“变量已声明但未使用”的错误,并提供了正确的变量使用方式,旨在帮助开发者避免此类常见的编译陷阱,提升代码的健壮性和可读性。 理解Go语言的变量声明…

    2025年12月16日
    000
  • Revel框架中模块化语言字符串的提取与管理

    本文探讨在revel框架中,如何高效地为api客户端提取特定模块和语言环境下的所有本地化字符串。鉴于revel默认的i18n机制是基于消息键值对的按需翻译,文章将分析其内部实现,并提出通过自定义函数、复制核心逻辑或向revel贡献代码等多种策略,以实现批量获取语言字符串的功能,并提供相应的实现思路和…

    2025年12月16日
    000
  • Revel框架中获取指定模块所有语言字符串的策略与实践

    本文探讨了在revel框架中获取特定模块下所有语言字符串的方法。鉴于revel的国际化机制默认不直接暴露所有翻译键值对,文章深入分析了其内部实现原理,并提供了包括自定义函数、修改框架源码或手动解析等多种解决方案,旨在帮助开发者实现api服务中多语言内容的灵活交付。 Revel国际化机制概述 Reve…

    2025年12月16日
    000
  • 使用Gorilla Mux创建带可选URL变量的路由

    本文详细介绍了如何在Go语言的Gorilla Mux路由框架中实现带有可选URL变量的路由。核心策略是通过注册两个独立的路由来处理有变量和无变量的两种情况,并在同一个处理器函数中利用`mux.Vars()`结合`ok`检查来判断可选变量是否存在,从而根据有无变量执行不同的业务逻辑。 在构建RESTf…

    2025年12月16日
    000
  • Go语言反射:动态创建指定类型的切片(Array)实例

    本文深入探讨了在go语言中如何利用反射机制动态创建指定类型的切片(slice)实例。我们将学习如何使用`reflect.makeslice`来创建具有初始长度和容量的切片,以及如何通过`reflect.zero`来生成一个nil切片,这在处理运行时未知类型或需要构建通用数据结构时尤为关键。 在Go语…

    2025年12月16日
    000
  • Go 语言中结构体方法调用:值类型与指针类型的区别

    本文旨在阐明 Go 语言中,当结构体方法接收者为指针类型时,通过结构体实例(值类型)和结构体指针调用该方法的差异。我们将深入探讨 Go 语言的隐式转换机制,解释为何这两种调用方式最终都能正确执行,并强调理解值类型和指针类型在方法调用中的重要性。 在 Go 语言中,方法是与特定类型关联的函数。当方法接…

    2025年12月16日
    000
  • Go 语言方法调用:结构体与结构体指针的区别

    本文深入探讨了 Go 语言中结构体方法调用的两种方式:直接在结构体实例上调用和通过指向结构体的指针调用。虽然两种方式通常都能得到相同的结果,但其底层机制存在差异。理解这些差异有助于编写更高效、更健壮的 Go 代码。本文将详细解释这两种调用方式的原理,并通过示例代码进行演示,帮助读者深入理解。 在 G…

    2025年12月16日
    000
  • Go并发编程:理解无缓冲通道的死锁

    本文深入探讨了Go语言中无缓冲通道导致死锁的原因。通过分析代码示例,解释了无缓冲通道的阻塞特性,以及在单goroutine中使用无缓冲通道为何会引发死锁。同时,提供了避免死锁的方案,并强调了并发编程中goroutine和通道的协同作用。 在Go语言的并发编程模型中,通道(channel)扮演着至关重…

    2025年12月16日
    000
  • Go语言中扩展或修改现有包函数行为:原理与替代方案

    go语言设计哲学不直接支持对现有包函数进行覆盖或猴子补丁。本文将深入探讨go语言为何缺乏此类机制,并提供三种实用的替代方案:通过自定义函数包装现有逻辑、分叉并修改原始包,或重新评估设计并选择更合适的库。这些方法能帮助开发者在保持go语言核心优势的同时,实现对外部包行为的灵活控制。 在Go语言的开发实…

    2025年12月16日
    000
  • Go语言中修改外部包函数行为的策略:原理与替代方案

    go语言的设计哲学阻止了直接重写或覆盖现有包的函数。本文旨在阐明go语言中为何无法直接进行此类操作,并提供三种实用的替代方案,帮助开发者在不直接修改第三方包代码的前提下,实现对外部函数行为的定制或扩展,包括包分叉、创建包装器函数以及重新设计或选择其他库。 Go语言以其简洁、高效和强类型特性而闻名。在…

    2025年12月16日
    000

发表回复

登录后才能评论
关注微信