本文仅供学习交流使用!
Java Record Class相关文章地址:
https://www.liaoxuefeng.com/wiki/1252599548343744/1331429187256353
https://www.baeldung.com/java-record-keyword
https://www.developer.com/java/java-record-class/
Java中的记录类是什么?
在处理 Java 项目时,作为开发人员,我们经常编写服务类、安全类或任何其他基本类。这些类本质上是功能性的。同样,程序员编写类的唯一目的通常是携带数据。例如,假设客户端从服务器请求一些数据,例如一个人的ID和姓名,并且服务器用适当的数据进行响应。由于Java中一切都是对象,因此必须有某个类来承载数据。服务器将类的对象返回给客户端。请注意,该对象的唯一目的是将数据从服务器传送到客户端。
现在,编写这样一个数据类,即使它可能是一个简单的 POJO,也包含大量样板代码,例如私有字段、构造函数、getter
和 setter
方法、hashCode()
、 equals()
和toString ( )
方法。由于 Java 语言的冗长性质,简单的载体类会变得繁重,包含大量不必要的代码。这些缺点导致引入了一种称为record
的特殊类型的类。此类聚合(或保存)一组值,而无需编写样板代码,并充当数据对象的有效载体。
事实上,开发人员可以在没有记录类的情况下管理一切,就像我们长期以来所做的那样。记录类在便利性和效率方面将数据载体类重新定义到另一个水平。
我们经常用作数据载体的一个简单的 POJO 类可能包含大量的样板代码。下面是在 Java 中创建此类的代码示例:
package org.example;
import java.util.Objects;
public class Person {
private int id;
private String name;
public Person() {
}
public Person(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return getId() == person.getId() && getName().equals(person.getName());
}
@Override
public int hashCode() {
return Objects.hash(getId(), getName());
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
如何在 Java 中创建记录类
Java 中的 Record类由上下文相关关键字record
支持。除非与记录声明一起使用,否则该关键字没有特殊含义。通常,在 Java 中使用以下语法声明记录:
record recordName(list-of-components) {
//可选语句
}
请注意,该声明与 Java 中的典型类声明有显着不同。该声明非常类似于以关键字record
开头,后跟记录名称的函数。该记录类的参数包含逗号分隔的组件列表。该组件列表指定记录将保存的数据。另请注意,记录的正文是可选的。
现在,假设程序员想要创建上述person
类的记录 - 开发人员可以使用以下 Java 代码示例声明该记录:
record Person(int id, String name){}
就是这样!我们准备创建此类的对象,如下所示:
Person p1 = new Person(1,”Peter Parker”);
在幕后,编译器自动提供存储数据所需的元素、构造函数、访问数据的 getter 方法、toString()
、equals()
和`hashCode()方法,而无需程序员的任何干预。因此,以下是有效的代码,尽管我们没有明确编写任何此类内容:
// toString方法的使用
System.out.println(p1.toString());
// getter方法的表现形式
System.out.println(p1.name());
package org.example;
record Person(int id, String name){}
public class App
{
public static void main( String[] args )
{
Person p1 = new PersonRecord(1,"Peter Parker");
Person p2 = new PersonRecord(2,"Spiderman");
System.out.println(p1.toString());
System.out.println(p1.equals(p2));
System.out.println(p1.name());
}
}
关于上面的代码示例,有几点需要注意:
- 记录类提供的规范构造函数包含与组件列表相同的参数,并且按相同的顺序传递。传递的值会自动分配给记录字段。
- 记录由
new
关键字实例化,就像在 Java 中创建任何其他对象一样。 - 记录中的数据保存在私有最终字段中,并且只有一个 getter 方法。因此,记录中的数据是不可变的。
- 记录不能继承另一个类。但是,所有记录都隐式继承
java.lang.Record
。因此,它重写了Object
类的equals()
、hashCode()
、toString()
方法。 - 所有记录声明都是最终的,因此不能延期。
- 然而,一条记录可以实现一个或多个接口。
- 除组件列表之外的任何其他字段都必须声明为静态。
Java 中的规范构造函数
规范构造函数具有特定于 Java 中记录类构造的预定义形式。但是,有两种方法可以声明我们自己的实现。在 Java 中声明规范构造函数的第一种方法是使用以下代码:
record Invoice(String id, float amount) {
static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
+String.valueOf(Calendar.getInstance().get(Calendar.MONTH)+1);
public Invoice(String id, float amount){
this.id=prefix+id.trim();
this.amount=amount;
}
}
另一种方法是声明一个紧凑的构造函数,其中签名的声明是隐式的。在这里,我们只需提供记录名称作为构造函数,不带任何参数。这种类型的构造函数具有所有参数的隐式声明(与记录组件相同),并自动分配给传递给记录组件的值。另请注意,在紧凑构造函数中,我们不使用 this 关键字。
record Invoice(String id, float amount) {
static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
+String.valueOf(Calendar.getInstance().get(Calendar.MONTH)+1);
public Invoice{
id=prefix+id.trim();
amount=amount;
}
}
Java 中的非规范构造函数
虽然有一个规范的构造函数就足够了,但程序员也可以声明一个非规范的构造函数,我们可能只想用默认值初始化记录字段的一个值。在这种情况下,开发人员可能会编写非规范的构造函数。非规范构造函数的关键要求是该构造函数*必须通过this
关键字调用记录中的另一个构造函数。这是一个简单的例子:
record Invoice(String id, float amount) {
static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
+String.valueOf(Calendar.getInstance().get(Calendar.MONTH)+1);
public Invoice{
id=prefix+id.trim();
amount=amount;
}
public Invoice(String id){
this(id,0.0f);
}
}
同时使用规范构造函数和非规范构造函数来声明记录是完全有效的,并且记录可以具有的构造函数的数量没有限制,只要它是根据记录的规范设计的。
有关 Java 构造函数的更多信息,可阅读:如何在 Java 中使用构造函数。
Java 记录类代码示例
下面是一个快速代码示例,展示了如何在 Java 中使用Record类、规范构造函数和非规范构造函数:
package org.example;
record Invoice(String id, float amount) {
static String prefix = String.valueOf(Calendar.getInstance().get(Calendar.YEAR))
+String.valueOf(Calendar.getInstance().get(Calendar.MONTH)+1);
public Invoice{
id=prefix+id.trim();
if(amount<0)
throw new IllegalArgumentException("-ve values not allowed");
amount=amount;
}
public Invoice(String id){
this(id,0.0f);
}
}
public class App
{
public static void main( String[] args )
{
float[] amt = {400.00f,600.00f,300.00f,700.00f,600.00f};
Invoice[] invoice = new Invoice[5];
for(int i=0;i<invoice.length;i++)
invoice[i] = new Invoice(String.valueOf(i+1), amt[i]);
for(int i=0;i<invoice.length;i++)
System.out.println(invoice[i].toString());
}
}
Record类的特点
- 带有全部参数的构造方法
- public 访问器
- toString(),hashCode(),equals()
- 无 set,get 方法。没有遵循 Bean 的命名规范
- final 类,不能继承 Record,Record 为隐士的 final 类。除此之外与普通类一样
- 不可变类,通过构造创建 Record
- final 属性,不可修改 不能声明实例属性,能声明 static 成员
最后
Java 的Record类除了作为数据载体之外,还可以有许多创新的用例。隐式使用java.lang.Record
类的关键字record的引入为其添加了另一层便利。毕竟,它是一个方便的类,专门设计用作数据载体,根据 Java 语言规范,它打破了 POJO 类声明的冗长性。开发人员完全可以放弃它并坚持旧的使用方式。