Java学习之旅第二季-21:记录
21.1 记录概述
记录(Record)是 Java 17 引入的语法特性,其目的是封装一个小的不可变类,用于创建不可变对象。
如果要实现一个不可变对象,可以想到的手段如下:
- 使类不可继承:final修饰类或使用private修饰构造方法
- 所有实例变量使用private和final修饰
- 不声明任何setter方法
- 不允许方法返回可变对象的引用
- 使用构造方法为属性赋值
不过开发者自己实现,显得有点繁琐,如果使用记录来实现则代码简洁不少。
21.2 记录声明
记录的声明使用关键字 record ,语法形式如下:
[修饰符] record 记录名(属性列表) [implements 接口] {}
属性列表:声明记录拥有的属性,也称为记录组件(Component)
编译时会自动增加以下内容:
- 构造方法:参数与声明时的属性列表一致,且会对属性赋值
- 访问属性的方法,方法名与属性同名,不能以wait、toStirng、 finalize命名
- toString方法,默认所有属性参与字符串拼接
- equals方法,默认所有属性参与比较
- hashCode方法,默认所有属性参与运算
记录示例
public record User(String name, int age){}
编译之后,完整类信息如下:
- 两个private final 修饰的成员name和age
- 带有name和age两个参数的public构造方法
- public修饰的name()和age()两个getter方法
- equals,hashCode和toString方法
与之对应的源码大致如下:
public final class User {private final String name;private final int age;public User(String name, int age) {this.name = name;this.age = age;}public String name() {return this.name;}public int age() {return this.age;}@Overridepublic String toString() {return "User[name=" + this.name + ", age=" + this.age + "]";}@Overridepublic boolean equals(Object obj) {if (obj == null) {return false;}if (obj instanceof User user) {if (name == null) {return user.name == null && age == user.age;} else {return name.equals(user.name) && age == user.age;}}return false;}@Overridepublic int hashCode() {return Objects.hash(name, age);}}
21.3 构造方法声明
刚才的声明中,没有看到有任何成员,默认情况下基本够用,但是我们仍然可以在其中声明成员:构造方法、普通方法、静态方法等,但是不能声明实例变量和代码块。
对应方法及静态方法没有什么特别的语法,不过由于 Record 本身是不可继承的,其中的方法使用protected修饰也没有意义。
本小节主要关注构造方法的声明。
默认情况下,记录会产生全部参数的构造方法,但是如果我们自己显式声明的话也是可行的。只是要注意语法规则:
-
声明参数与属性列表一致的构造方法,则不会产生默认的构造方法
-
构造方法不能声明抛出异常
-
不能使用this调用其他构造方法
-
必须在构造方法中为属性赋值,因为默认产生的属性是final修饰的且未赋初始值。
public record User(String name, int age){public User(String name, int age){this.name = name;this.age = age;}
}
紧凑构造方法
紧凑的构造方法即是全参构造方法的简化版,使用语法如下:
public User{
}
这种简化写法会隐式赋值给属性,且不支持显式赋值。且支持先对构造方法的参数进行运算,再隐式将其赋值到属性。
public User{if(name==null){name="";}age += 10;
}
带部分参数的构造方法
如果不需要未所有属性赋值,也可以声明带部分参数的构造方法,语法如下:
public User(String name){this(name,0);
}
但是这些写法,方法体中需要显式调用全参构造方法,且不能显式为属性赋值。
21.4 记录用于instanceof类型匹配
记录也支持 instanceof 的类型匹配语法
public void test(Object o){if(o instanceof User(String name,int age)){System.out.println(name + "," + age);}
}
上面的方法中,需要对形参 o判断是否是记录User的类型,所以使用了instanceof运算符,不过可以看到,在其后的小括号中声明了它的两个属性,这样在 if 条件成立时,就可以在后面代码块中直接使用这两个属性了。
21.5 记录的本质
所有的记录都是继承自 java.lang.Record 类,该类是一个抽象类,但不允许开发者直接继承。其声明如下:
public abstract class Record {protected Record() {}@Overridepublic abstract boolean equals(Object obj);@Overridepublic abstract int hashCode();@Overridepublic abstract String toString();
}
只提供了受保护的构造方法,其他三个方法只是简单重写了Object中的三个方法:toString,equals,hashCode,且仍然保持抽象声明。
21.6 小结
Java 17引入的记录(Record)是一种简化不可变类定义的语法特性。通过 record 关键字声明,自动生成final类、私有final属性、全参构造方法、属性访问器(如name()
)以及 equals/
hashCode/
toString 方法。记录支持紧凑构造方法(隐式赋值)和部分参数构造方法(需调用全参构造),但不能声明实例变量或代码块。所有记录隐式继承 java.lang.Record 抽象类,适用于 instanceof 类型匹配(如 User(String name, int age))。其核心目的是以简洁语法替代手动实现不可变类的繁琐过程。