我报名参加金石计划1期挑战——瓜分10万奖池,这是我的第2篇文章,点击查看活动详情
record 定义
java 中 record 这个功能,是在 JDK 14 以预览版形式发布的,在 JDK 16 中才正式发布
record 档案类是用来表示 不可变数据的透明载体
不可变数据:是指档案类一旦创建就不能改变了
透明载体:是指档案类帮我们默认实现了其中的一些方法,这些方法可以直接使用,也可以自己替换掉
record 关键字的使用
public record User(String name, Integer age) {
}
- 上面这段代码创建的是一个类名为 User 的类,不是方法;
- 使用 record 关键字替换了 class 关键字,用来标识该类是档案类;
- 小括号内的是该类声明的参数,可以看成是构造方法;
- 大括号内的,就是该类的具体实现代码了,但是现在也不需要声明变量,也不需要写构造方法;
使用 User 对象,并赋值和读取数据
public class Main {
public static void main(String[] args) {
// 创建user对象
User user = new User("张三", 20);
System.out.println(user.name());
System.out.println(user.age());
System.out.println(user);
}
}
输出的结果
张三
20
User[name=张三, age=20]
档案类一旦创建,就不能再改变里面的值了,所以除了构造方法外,就没有给参数赋值的地方了。
而且如果要声明其它的字段,也只能是 静态 的,声明方法也是 静态 的
下面是声明静态变量和方法的示例
public record User(String name, Integer age) {
/**
* 声明静态变量
*/
static final Integer SEX = 1;
/**
* 声明静态方法
*
* @param name 姓名
* @return User
*/
static User noAgeUser(String name) {
return new User(name, 0);
}
}
使用的话,直接通过类名就可以调用静态成员
public class Main {
public static void main(String[] args) {
System.out.println(User.SEX);
User user = User.noAgeUser("李四");
System.out.println(user);
}
}
到这里就解释了不可变数据的意思:一旦创建,里面的数据就不能改变了!
内置缺省方法(透明载体)
档案类已经帮我们写好了以下这些方法
- 构造方法
- equals() 方法
- hashCode() 方法
- toString() 方法
- 读取不可变数据的方法
怎样验证上面这些方法是真的内置好的呢?
首先是构造方法,我们在上面创建 User 对象的时候就使用了,
如果没有有参构造方法的话,是无法直接 new 并传参的
User user = new User("张三", 20);
equals() 和 hashCode() 方法,我们来验证一下
public static void main(String[] args) {
User user1 = new User("张三", 20);
User user2 = new User("张三", 20);
System.out.println(user1.equals(user2));
// 这里输出为 true
}
创建两个对象,入参一致,这个时候控制台输出的结果为 true
这就表明,档案类已经帮我们重写了 equals() 和 hashCode() 这两个方法
如果没有重写,那这里输出的肯定是 false,因为创建的两个对象内存地址是不一样的
toString() 方法我们在上面直接输出对象的时候,也看到了
System.out.println(user);
输出的是
User[name=张三, age=20]
如果没有重写 toString() 方法的话,那输出的应该是该对象的内存地址,像下面这样
com.example.demo.User@2328c243
重写默认实现
同样的,上述几个内置的方法,我们也可以使用 @Override 进行重写,替换掉默认的实现
除了构造方法不用 @Override 注解(其实其它的方法也可以不用加,但是代码规范最好还是加上)
public record User(String name, Integer age) {
/**
* 重写构造方法,不需要 @Override 注解
*/
public User {
System.out.println("重写了构造方法");
}
/**
* 重写 getName()
*
* @return
*/
@Override
public String name() {
return name;
}
/**
* 重写 getAge()
*
* @return
*/
@Override
public Integer age() {
return age + 1;
}
/**
* 重写 equals
*
* @param obj the reference object with which to compare.
* @return
*/
@Override
public boolean equals(Object obj) {
return false;
}
/**
* 重写 hashCode
*
* @return
*/
@Override
public int hashCode() {
return 0;
}
/**
* 重写 toString
*
* @return
*/
@Override
public String toString() {
return null;
}
}
到这里解释了透明载体:默认实现了其中的一些方法,这些方法可以直接使用,也可以自己替换掉。
一般情况下,档案类给我们内置好的这些方法是可以满足需求的,不需要去进行重写替换。
常用的可能是重写构造方法,在重写的方法里,对数据做一些判断
public record User(String name, Integer age) {
/**
* 重写构造方法,不需要 @Override 注解
*/
public User {
System.out.println("重写了构造方法");
if (age < 0) {
throw new IllegalArgumentException("年龄不正确");
}
}
}
public class Main {
public static void main(String[] args) {
User user = new User("张三", -1);
System.out.println(user);
}
}
这样的话,就会抛出一个异常
重写了构造方法
Exception in thread "main" java.lang.IllegalArgumentException: 年龄不正确
at com.example.demo.User.<init>(User.java:15)
at com.example.demo.Main.main(Main.java:11)
总结一下档案类的一些限制
- 档案类是 final 的,不支持继承
- 档案类中声明的变量是不可变变量
- 档案类中声明其它字段和方法只能是静态的(static)
- 档案类不能抽象(abstract)
使用场景
使用场景的话,我觉得在多线程情况下,使用档案类,数据肯定是安全的,不用考虑并发下数据安全问题,因为数据不可变嘛
再有就是它是基于值的比较,省的我们再写一遍 equals() 和 hashCode() 这两个方法
另外这也算是内置实现了 lombok 的一些功能