record类型是从14开始预览到16成为正式版的,record类型是一种受限制的类,一般用来封装不可变对象,record类型会自动生成一个全部属性的构造方法,以及属性的get方法,但没有set方法,会自动生成hashCode()、equals()、toString()方法;(有点像Lombok的@Data功能)
另外自动生成的get方法不会使用getXxxx()的名字,而是直接用xxxx(),没有get这个单词前缀;
record生成的类是final修饰的,并且只有一个java.lang.Record父类,不能继承也不能被继承,但是可以实现接口,record类里也可以有实例方法、静态属性和静态方法,但是不能有实例属性,也可以有自定义的构造方法,构造方法里再用this(xxxx)调用自动生成的构造方法,也可以使用不带括号和参数的构造方法对自动生成的构造方法进行调整;
定义一个record类型很简单,可以在独立文件里定义:
package test;
public record MyRecord(String name, int age) {
}
也可以定义成类属性:
public record MyRecord2(int x, int y) {}
也能定义在方法内部:
public void test() {
record MyRecord3(String s) {}
}
用来临时做一些记录很方便;
可以用javap看一下record类型自动生成的类的样子:
先定义一个名叫A.java的record类型:
然后javac A.java编译下,再用javap -p A.class查看属性和方法:
可以看到是一个final类并且继承java.lang.Record类,所有自动生成的方法都是public的,属性是private final的;
另外Class类还新增了用来处理Record类型的方法:
public boolean isRecord():判断class是不是record类型;
public RecordComponent[] getRecordComponents():返回记录组件,可用来反射动态调用;
测试demo:
MyRecord类:
package test;
public record MyRecord(String name, int age) {
private static String info = "这是一个用于记录name和age的record";
public MyRecord {
name = name.toUpperCase(); //生成的构造方法里将名字变大写
age = age + 1; //生成的构造方法里将age都加1
}
public MyRecord(String firstName, String lastName, int age) {
this("%s %s".formatted(firstName, lastName), age);
}
public void say() {
System.out.println("你好,我是" + name);
}
public static String getRecrodInfo() {
return info;
}
}
main测试类:
package test;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.RecordComponent;
public class MainTest {
public record MyRecord2(int x, int y) {}
public static void main(String[] args) {
MyRecord x = new MyRecord("Tom", 12);
System.out.println(x.name());
System.out.println(x.age());
System.out.println(x);
System.out.println("IsRecord=" + MyRecord.class.isRecord());
System.out.println("=".repeat(40));
RecordComponent[] comp = MyRecord.class.getRecordComponents();
for (RecordComponent c : comp) {
System.out.println("RecordComponent:" + c);
Method method = c.getAccessor();
try {
System.out.println("_method:" + method);
System.out.println("_method result:" + method.invoke(x, null));
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
e.printStackTrace();
}
}
System.out.println("=".repeat(40));
MyRecord x2 = new MyRecord("John", "Smith", 23);
System.out.println(x2);
x2.say();
System.out.println(MyRecord.getRecrodInfo());
}
public void test() {
record MyRecord3(String s) {}
}
}
运行结果:
实现接口的小例子:
package test;
public class MainTest {
interface MyInterface {
void fun();
}
record MyRecord(String s) implements MyInterface {
@Override
public void fun() {
System.out.println("s=" + s);
}
}
public static void main(String[] args) {
MyRecord r = new MyRecord("HELLO WORLD");
System.out.println(r);
r.fun();
}
}
结果: