【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() {...}
}

可见,记录类自动声明以下成员:

  1. 记录类类头(签名)用括号 () 声明类中字段,这些字段都是由 private final 修饰;
  2. 记录类会自动声明和字段名称相同的 public Getter,用于外部获取对应字段的值;
  3. 一个和记录类签名相同的标准构造器,字段的赋值顺序同签名中字段的顺序;
  4. equals()hashCode() 方法实现,指定了两个实例必须同属于同一个记录类类型且字段值对应相等时,二者相等;
  5. 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));
        }
    }
}

可见,紧凑构造器具有如下特性:

  1. 省略形参列表。形参列表同记录类中的签名;
  2. 省略字段赋值。字段赋值语句不需要显式声明在紧凑构造器中,而是会在显式声明语句执行完后,最后按类头签名的字段顺序赋值;

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

显式声明成员的限制

  1. 在纪录类中手动显式声明的字段,只能够是静态变量,不支持实例变量;
  2. 可以手动显式地声明新的方法,这些方法可以是实例方法,也可以是静态方法,但不能有抽象方法和原生方法(native);
  3. 若隐式声明的方法(Getters、equals(), hashCode())需要变动,可以手动显式声明,但这些方法的特点和行为必须符合 Record 类的要求;
  4. 允许添加静态代码块,但不允许匿名代码块;
  5. 记录类内部也可以声明内部类,且内部类也可以是记录类;

5-12.4 记录类的共同基类

所有的纪录类都默认继承自 Record 类,该类位于 java.lang,是一个抽象类。类中只有以下方法:

构造方法

构造方法 描述
protected Record() 由记录类调用

抽象方法

抽象方法 实现要求
boolean equals() 纪录类要求,两个记录实例当且仅当属于同一记录类,并且字段对应值相等时才相等
int hashCode() 纪录类要求,两个记录实例的 equals() 方法若为真,则两个实例的 hashCode 应当相等
String toString() 返回该对象的字符串表示,内容由类名、字段名和字段值组成
posted @ 2023-10-08 19:06  Zebt  阅读(75)  评论(0)    收藏  举报