详解Java的record关键字
record关键字
record关键字主要提供了更简洁、更紧凑的final修饰的不可变数据类的定义方式。可以用于数据传输,并发编程等领域。
该特性最早于Java 14引入开始孵化,经历两次孵化,最终于Java 16转为正式特性。
使用方法及示例
在Java日常开发中,当我们需要定义个不可变数据类对象用于数据传输,并发编程等途径时。通常写法如下代码块所示.
以下示例代码块为了突显class和record的getter方法命名规则的差异,故意修改等效于record的x()和y()方法. 常规的getter方法命名方式应该为getX()和getY()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int x() {
return x;
}
public int y() {
return y;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
@Override
public int hashCode() {
return Objects.hash(x, y);
}
}
使用record实现上面等同效果仅需简单的一行即可。
1
2
public record PointR(int x, int y) {
}
通过简单的对比,我们可以得知,record相当于节省了以下几个方面的代码。
- 全参数的构造函数
- getter方法
- hashCode和equals方法
- toString方法
- final修饰的类
定义静态属性字段,静态方法、类方法和属性字段注解
record内部 不允许 定义非静态属性字段. 除此之外,和class的用法基本上没有区别。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public record PointR(@Nullable int x, int y) {
/**
* 1. 定义静态属性字段
*/
private static int z = 1;
/**
* 2. 定义静态方法
*/
public static int distance(PointR o, PointR o1) {
return 0;
}
/**
* 3. 定义方法
*/
public int distance(PointR o) {
return 0;
}
}
实现接口
record关键字隐式继承Record类,所以 不允许 在使用 extends 继承其他类。和class一样是单根继承,多接口实现。
1
2
3
4
5
6
7
8
// 扩展实现其他接口
public record PointR(int x, int y) implements Comparable<PointR> {
@Override
public int compareTo(PointR o) {
return 0;
}
}
泛型
1
2
3
4
5
6
7
8
// Record使用泛型
public record PointR<R extends Serializable>(int x, int y, R r) {
public static void main(String[] args) {
// 测试
PointR<ArrayList<Integer>> pointR = new PointR<>(1, 2, new ArrayList<Integer>());
}
}
浅拷贝
record和class一样,实现Cloneable接口后,针对引用类型都是默认浅拷贝. 在并发环境时,需要考虑是否会受到浅拷贝影响。
1
2
3
4
5
6
7
8
public record PointR(int x, int y) implements Cloneable {
@Override
protected Object clone() throws CloneNotSupportedException {
// 并发环境时,需要考虑是否会受到浅拷贝影响
return super.clone();
}
}
反射
相比于class的反射获取属性字段信息方式, record的反射有了颠覆性的变动,我个人感觉是更加简单和直观。
可以通过Class定义的geRecordComponents()方法获取record字段的record组件数组,顺序等同于record构造函数中定义的顺序。
1
RecordComponent[] recordComponents = PointR.class.getRecordComponents();
获取字段类型
Class对象中新增 isRecord() 方法用于区分类是否是record类.
1
PointR.class.isRecord()
其他常用的反射相关的方法基本上类似于Field。例如:RecordComponent#getType() 反射获取属性字段的类型, RecordComponent#getAnnotation() 反射获取属性字段的注解
1
2
3
4
5
6
RecordComponent[] recordComponents = PointR.class.getRecordComponents();
for (RecordComponent rc : recordComponents) {
Assertions.assertEquals(int.class, rc.getType());
rc.getAnnotation(Nullable.class)
}
本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议 进行许可。欢迎转载、使用、重新发布,但务必保留文章署名 TinyZ Zzh (包含链接: https://tinyzzh.github.io ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。 如有任何疑问,请 与我联系 (tinyzzh815@gmail.com) 。
评论