【Java面向对象】5-12 记录类
5-12 记录类
注意:该部分属于进阶内容,建议至少学习完集合框架后再来了解。
5-12.1 声明和使用记录类
在实际开发中,往往会需要 final
类作为数据传输的载体。Java 的面向对象特性虽然能够满足这一需求,但以传统方式声明一个 final
类,严厉的语法规范和冗长的定义使得这一过程变得繁杂。自 Java 16 起,引入了记录类以解决这一问题。
Java 语言更新文档中记录类介绍:Record Classes (oracle.com)
有关纪录类的提案:JEP 395: Records (openjdk.org)
声明方法:使用关键字 record
以声明一个记录类。
示例:一个最简单的记录类。
// 该示例摘自 Java 语言更新文档
record Rectangle(double length, double width) {}
该记录类等价于以下普通类:
public final class Rectangle {
private final double length;
private final double width;
public Rectangle(double length, double width) {
this.length = length;
this.width = width;
}
public double length() { return this.length; }
public double width() { return this.width; }
// equals() 和 hashCode() 方法实现
// 当且仅当两个记录实例同属于同一个记录类,且字段值对应相等时,对象相等,哈希值相等
public boolean equals() {...}
public int hashCode() {...}
// toString() 方法实现
// 该记录实例所有字段的名称及其值的字符串表示
public String toString() {...}
}
可见,记录类自动声明以下成员:
- 记录类类头(签名)用括号
()
声明类中字段,这些字段都是由private final
修饰; - 记录类会自动声明和字段名称相同的
public
Getter,用于外部获取对应字段的值; - 一个和记录类签名相同的标准构造器,字段的赋值顺序同签名中字段的顺序;
equals()
和hashCode()
方法实现,指定了两个实例必须同属于同一个记录类类型且字段值对应相等时,二者相等;toString()
方法实现,为该记录实例所有字段的名称及其值的字符串表示;
使用方法:记录类也是一种类,可以使用 new
运算符创建新实例。
Rectangle r = new Rectangle(3, 4);
5-12.2 记录类中的构造器
默认情况下,记录类的构造器会自动声明。也可以由开发者在记录类中手动声明,以检查参数合法性并在必要时抛出异常。
手动声明一个标准构造器:
// 该示例摘自 Java 语言更新文档
record Rectangle(double length, double width) {
public Rectangle(double length, double width) {
if (length <= 0 || width <= 0) {
throw new IllegalArgumentException(
String.format("Invalid dimensions: %f, %f", length, width));
}
this.length = length;
this.width = width;
}
}
但这样的声明难免重复,易出错误。为了避免这种情况,可以声明一个紧凑构造器。
手动声明一个紧凑构造器:
// 该示例摘自 Java 语言更新文档
record Rectangle(double length. double width) {
public Rectangle {
if (length <= 0 || width <= 0) {
throw new IllegalArgumentException(
String.format("Invalid dimensions: %f, %f", length, width));
}
}
}
可见,紧凑构造器具有如下特性:
- 省略形参列表。形参列表同记录类中的签名;
- 省略字段赋值。字段赋值语句不需要显式声明在紧凑构造器中,而是会在显式声明语句执行完后,最后按类头签名的字段顺序赋值;
5-12.3 显式声明记录类成员
除了在记录类的签名处声明类的成员,还可以在记录类中显式声明其他成员。
手动声明记录类成员:
// 该示例摘自 Java 语言更新文档
record Rectangle(double length, double width) {
// 静态字段
static double goldenRatio;
// 静态代码块
// 用于静态字段初始化
static {
goldenRatio = (1 + Math.sqrt(5)) / 2;
}
// 静态方法
public static Rectangle createGoldenRectangle(double width) {
return new Rectangle(width, width * goldenRatio);
}
// Getter
public double length() {
System.out.println("Length is " + length);
return length;
}
}
显式声明成员的限制:
- 在纪录类中手动显式声明的字段,只能够是静态变量,不支持实例变量;
- 可以手动显式地声明新的方法,这些方法可以是实例方法,也可以是静态方法,但不能有抽象方法和原生方法(
native
); - 若隐式声明的方法(Getters、
equals()
,hashCode()
)需要变动,可以手动显式声明,但这些方法的特点和行为必须符合Record
类的要求; - 允许添加静态代码块,但不允许匿名代码块;
- 记录类内部也可以声明内部类,且内部类也可以是记录类;
5-12.4 记录类的共同基类
所有的纪录类都默认继承自 Record
类,该类位于 java.lang
,是一个抽象类。类中只有以下方法:
构造方法:
构造方法 | 描述 |
---|---|
protected Record() |
由记录类调用 |
抽象方法:
抽象方法 | 实现要求 |
---|---|
boolean equals() |
纪录类要求,两个记录实例当且仅当属于同一记录类,并且字段对应值相等时才相等 |
int hashCode() |
纪录类要求,两个记录实例的 equals() 方法若为真,则两个实例的 hashCode 应当相等 |
String toString() |
返回该对象的字符串表示,内容由类名、字段名和字段值组成 |