实战 Java 16 值类型 Record - 2. Record 的基本用法

在上一篇文章实战 Java 16 值类型 Record - 1. Record 的默认方法使用以及基于预编译生成相关字节码的底层实现中,我们详细分析了 Record 自带的属性以及方法和底层字节码与实现。这一篇我们来详细说明 Record 类的用法。

声明一个 Record

Record 可以单独作为一个文件的顶级类,即:
User.java 文件:

public record User(long id, String name, int age) {}

也可以作为一个成员类,即:

public class RecordTest { public record User(long id, String name, int age) {} }

也可以作为一个本地类,即:

public class RecordTest { public void test() { record Mail (long id, String content){} Mail mail = new Mail(10, "content"); } }

不能用 abstract 修饰 Record 类,会有编译错误。
可以用 final 修饰 Record 类,但是这其实是没有必要的,因为 Record 类本身就是 final 的

成员 Record 类,还有本地 Record 类,本身就是 static 的,也可以用 static 修饰,但是没有必要。

和普通类一样,Record 类可以被 public, protected, private 修饰,也可以不带这些修饰,这样就是 package-private 的。

和一般类不同的是,Record 类的直接父类不是 java.lang.Object 而是 java.lang.Record。但是,Record 类不能使用 extends,因为 Record 类不能继承任何类。

Record 类的属性

一般,在 Record 类声明头部指定这个 Record 类有哪些属性

public record User(long id, String name, int age) {}

同时,可以在头部的属性列表中运用注解:

@Target({ ElementType.RECORD_COMPONENT}) @Retention(RetentionPolicy.RUNTIME) public @interface A {} @Target({ ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface B {} public record User(@A @B long id, String name, int age) {}

但是,需要注意一点,这里通过反射获取 id 的注解的时候,需要通过对应的方式进行获取,否则获取不到,即 ElementType.FIELD 通过 Field 获取,ElementType.RECORD_COMPONENT 通过 RecordComponent 获取:

Field[] fields = User.class.getDeclaredFields(); Annotation[] annotations = fields[0].getAnnotations(); // 获取到注解 @B RecordComponent[] recordComponents = User.class.getRecordComponents(); annotations = recordComponents[0].getAnnotations(); // 获取到注解 @A Record 类体

Record 类属性必须在头部声明,在 Record 类体只能声明静态属性

public record User(long id, String name, int age) { static long anotherId; }

Record 类体可以声明成员方法和静态方法,和一般类一样。但是不能声明 abstract 或者 native 方法

public record User(long id, String name, int age) { public void test(){} public static void test2(){} }

Record 类体也不能包含实例初始化块,例如:

public record User(@A @B long id, String name, int age) { { System.out.println(); //编译异常 } } Record 成员

Record 的所有成员属性,都是 public final 非 static 的,对于每一个属性,都有一个对应的无参数返回类型为属性类型方法名称为属性名称的方法,即这个属性的 accessor。前面说这个方法是 getter 方法其实不太准确,因为方法名称中并没有 get 或者 is 而是只是纯属性名称作为方法名。

这个方法如果我们自己指定了,就不会自动生成:

public record User(long id) { @Override public long id() { return id; } }

如果没有自己指定,则会自动生成这样一个方法:

方法名就是属性名称

返回类型就是对应的属性类型

是一个 public 方法,并且没有声明抛出任何异常

方法体就是返回对应属性

如果属性上面有任何注解,那么这个注解如果能加到方法上那么也会自动加到这个方法上。例如:

public record User(@A @B long id, String name, int age) {} @Target({ ElementType.RECORD_COMPONENT, ElementType.METHOD, }) @Retention(RetentionPolicy.RUNTIME) public @interface A {} @Target({ ElementType.FIELD}) @Retention(RetentionPolicy.RUNTIME) public @interface B {}

下面获取 id() 这个方法的注解则会获取到注解 @A

Method id = User.class.getDeclaredMethod("id"); Annotation[] idAnnotations = id.getAnnotations(); //@A

由于会自动生成这些方法,所以 Record 成员的名称不能和 Object 的某些不符合上述条件(即上面提到的 6 条)的方法的名称一样,例如:

public record User( int wait, //编译错误 int hashcode, //这个不会有错误,因为 hashcode() 方法符合自动生成的 accessor 的限制条件。 int toString, //编译错误 int finalize //编译错误) { }

Record 类如果没有指定,则默认会生成实现 java.lang.Record 的抽象方法,即hashcode(), equals(), toStrng() 这三个方法。这三个方法的实现方式,在第一节已经详细分析过,这里简单回顾下要点:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zwpyzx.html