java 核心技术-12版 卷Ⅰ- 4.7.1 记录 record

createh51个月前 (04-05)技术教程7

原文

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);

如果希望记录实例是不可变的,那么字段就不能使用可变的类型。

提示: 对于完全由一组变量表示的不可变数据,要使用记录而不是类。如果数据是可变的,或者数据表示可能随时间改变,则使用类。记录更易读、更高效,而且在并发程序中更安全。

相关文章

java 核心技术-12版 卷Ⅰ- 4.8.7 设置类路径

原文4.8.7 设置类路径最好使用 -classpath(或 -cp, 或者Java 9 中的 --calss-path) 选项指定类路径:java -classpath /home/user/cla...

java 核心技术-12版 卷Ⅰ- 5.4 对象包装器与自动装箱

原文5.4 对象包装器与自动装箱有时,需要将 int 这样的基本类型转换为对象。所有的基本类型都有一个与之对应的类,例如,Integer类对应基本类型 int。通常,这些类称为包装器 (wrapper...

Java核心知识 Zookeeper(二)角色

Zookeeper 集群是一个基于主从复制的高可用集群,每个服务器承担如下三种角色中的一种 Leader1. 一个 Zookeeper 集群同一时间只会有一个实际工作的 Leader,它会发起并维护与...

Java面试核心技能全景解析:架构设计与编码能力的深度碰撞

Java面试核心技能全景解析:架构设计与编码能力的深度碰撞——技术深水区的破局之道在2024年互联网技术迭代浪潮中,Java工程师的面试战场早已从基础语法跃迁至复杂系统设计维度。本文以实战视角拆解分布...

Nacos Client服务订阅机制之「核心流程」

原文链接:https://mp.weixin.qq.com/s/ytKmp_V-zHUqgUFKcTWfMg原作者:程序新视界学习不用那么功利,二师兄带你从更高维度轻松阅读源码~说起Nacos的服务订...