java 核心技术-12版 卷Ⅰ- 4.7.1 记录 record
原文
4.7 记录
有时,记录就只是数据,而面向对象程序设计提供的数据隐藏有些碍事。考虑一个类Point ,这个类描述平面上的一个点,有x和y 坐标。
当然,可以如下创建一个类
public class Point {
public Point(double x,double y){
this.x = x;
this.y = y;
}
private final double x;
private final double y;
public double getX(){
return x;
}
public double getY(){
return y;
}
@Override
public String toString() {
return "Point[x=%d, y= %d]".formatted(x,y);
}
}
这里隐藏了x和y ,然后通过获取方法来获得这些值,不过,这种做法对我们确实有好处吗?
我们将来想改变Point的实现吗? 当然,还有极坐标,不过对于图形API ,你可能不会使用极坐标。在实际中,平面上的一个点就用x 和y 坐标来描述。
为了更简洁地定义这些类,JDK 14 引入了一个预览特性:“记录”(record)。最终版本在JDK 16 中发布。
4.7.1 记录概念
记录(record)是一种特殊形式的类,其状态不可变,而且公共可读。可以如下将Point 定义为一个记录:
record Point(double x ,double y){}
其结果是有一下实例字段的类
private final double x;
private final double y;
在Java语言规范中,一个记录的实例字段称为组件(component)。
这个类有一个构造器
Point(double x,double y)
和以下访问器方法
public double x()
public double y()
注意,访问器方法名为 x 和 y ,而不是getX 和 getY。(Java中实例字段可以与方法同名,这是合法的。)
var p = new Point(3,4);
System.out.println(p.x() + " " + p.y());
注释:Java没有遵循get 的约定,因为那有些麻烦。对于布尔字段,通常使用is 而不是get。而且首字母大写可能有问题。如果一个类既有x字段又有X字段,会发生什么?有些程序员不太满意,因为他们原来的类不能轻松地变为记录。不过实际上,那些遗留类中,很多都是可变的,所以并不适合转为记录。
除了字段访问器方法,每个记录有3个自动定义的方法:toString 、equals 和 hashCode 。下一章会更多地了解这些方法。
警告:对于这些自动提供的方法,也可以定义你自己的版本,只要它们有相同的参数和返回类型。例如,下面的定义就是合法的:
record Point(double x,double y){
public double x() {
return y; // Bad 语法允许,但实际开发中非常不推荐
}
}
可以为一个记录增加你自己的方法:
public record PointRecord(double x, double y) {
public double distanceFromOrigin (){
return Math.hypot(x, y);
}
}
与所有其他类一样,记录可以有静态字段和方法:
public record Point(double x, double y) {
public static Point ORIGIN = new Point(0,0);
public static double distance(Point p,Point q){
return Math.hypot(p.x -q.x , p.y -q.y);
}
}
不过,不能为记录增加实力字段:
record Point(double x ,double y){
private double r ;// ERROR
}
警告:记录的实例字段自动为final 手段。不过,它们可能是可变对象的引用。
record PointInTime(double x, double y, Date when){}
这样的实例将是可变的;
var pt = new PointInTime(0 ,0 , new Date());
p.when().setTime(0);
如果希望记录实例是不可变的,那么字段就不能使用可变的类型。
提示: 对于完全由一组变量表示的不可变数据,要使用记录而不是类。如果数据是可变的,或者数据表示可能随时间改变,则使用类。记录更易读、更高效,而且在并发程序中更安全。