概述
Record 在 JDK 16 正式发布
Record 用来表示不可变数据 的透明载体
OOP
封装 + 继承 + 多态
1 2 3 public interface Shape { double getArea () ; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Circle implements Shape { private double radius; @Override public double getArea () { return Math.PI * radius * radius; } public void setRadius (double radius) { this .radius = radius; } public double getRadius () { return radius; } }
同步方法 - 吞吐量大幅下降
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class Circle implements Shape { private double radius; @Override public synchronized double getArea () { return Math.PI * radius * radius; } public synchronized void setRadius (double radius) { this .radius = radius; } public synchronized double getRadius () { return radius; } }
不可变对象 + 公开不可变属性 - 一旦实例化,就不允许修改对象属性
1 2 3 4 5 6 7 8 9 10 11 12 13 public class Circle implements Shape { public final double radius; public Circle (double radius) { this .radius = radius; } @Override public double getArea () { return Math.PI * radius * radius; } }
公开 的只读变量 - 通过 final 修饰
公开的只读变量,只在公开的构造方法 中赋值 - 对象初始化
公开的只读变量,替换 了公开 的只读方法
Record
record 关键字是 class 关键字的一种特殊表现形式 ,用来标识档案类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public record Circle (double radius) implements Shape { @Override public double getArea () { return Math.PI * radius * radius; } public static void main (String[] args) { Circle circle = new Circle (10.0 ); double v = circle.radius(); } }
改进
比较两个实例是否相等,需要重写 equals 和 hashCode - 难以正确编写
档案类内置 了缺省 的 equals、hashCode、toString 的实现
减少代码数量 + 提高编码效率 + 减少编码错误 + 提高编码质量
不可变数据
Java 档案类是一种特殊形式的 Java 类
如果一个 Java 类一旦实例化 就不能再修改 ,那么它表述的数据为不可变数据
档案类不支持 extends ,隐含的父类 为 java.lang.Record ,因此无法通过修改父类来影响档案类的行为
档案类是 final 的,不支持子类 ,也不能是抽象类 ,因此无法通过修改子类来改变档案类的行为
档案类中声明的变量是不可变的变量
档案类不能声明可变的变量 ,也不能支持实例初始化 的方法
只能使用档案类形式 的构造函数 ,避免额外的初始化 对可变性 的影响
档案类不能声明 native 方法 ,否则打开了修改不可变变量 的后门
透明载体
档案类内置了方法的缺省 实现(可替换 ) - 构造方法、equals、hashCode、toString、不可变数据的读取方法
除了构造方法 ,其它的替换方法都可以使用 Override 注解来标注
透明载体 - 档案类承载有缺省实现 的方法,直接使用 或者替换
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 public record RecordCircle (double radius) implements Shape { public RecordCircle (double radius) { this .radius = radius; } @Override public double getArea () { return Math.PI * radius * radius; } @Override public boolean equals (Object obj) { if (this == obj) { return true ; } if (obj instanceof RecordCircle other) { return other.radius == this .radius; } return false ; } @Override public int hashCode () { return Objects.hash(this .radius); } @Override public String toString () { return String.format("RecordCircle[radius=%f]" , this .radius); } @Override public double radius () { return this .radius; } }
构造方法
要在构造方法中对档案类声明的变量 添加必要的检查 compact constructor - 构造函数自动声明参数和自动赋值
equals + hashCode
如果采用档案类的缺省 实现,equals 和 hashCode 方法的行为可能无法预测 数组没有重写 equals 和 hashCode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 jshell> record Password (byte [] password) {}; | created record Password jshell> Password p1 = new Password ("123456" .getBytes()); p1 ==> Password[password=[B@433c675d] | created variable p1 : Password jshell> Password p2 = new Password ("123456" .getBytes()); p2 ==> Password[password=[B@1a6c5a9e] | created variable p2 : Password jshell> p1.equals(p2) $5 ==> false | created scratch variable $5 : boolean
String 重写 equals 和 hashCode
1 2 3 4 5 6 7 8 9 10 11 12 13 14 jshell> record Password (String password) {}; | created record Password jshell> Password p1 = new Password ("123456" ); p1 ==> Password[password=123456 ] | created variable p1 : Password jshell> Password p2 = new Password ("123456" ); p2 ==> Password[password=123456 ] | created variable p2 : Password jshell> p1.equals(p2) $5 ==> true | created scratch variable $5 : boolean
不推荐重写
不可变数据的读取方法 - 可能会打破实例状态,导致行为不可预测
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 jshell> record Number(int x) { ...> public int x() { ...> return x > 0 ? x : (-1)*x; ...> } ...> } | created record Number jshell> Number n = new Number(-1); n ==> Number[x=-1] | created variable n : Number jshell> n.x(); $3 ==> 1 | created scratch variable $3 : int jshell> Number m = new Number(n.x()); m ==> Number[x=1] | created variable m : Number jshell> m.equals(n); $5 ==> false | created scratch variable $5 : boolean