继续浏览精彩内容
慕课网APP
程序员的梦工厂
打开
继续
感谢您的支持,我会继续努力的
赞赏金额会直接到老师账户
将二维码发送给自己后长按识别
微信支付
支付宝支付

无涯教程- Java 14 – Record类型介绍

GeekGay
关注TA
已关注
手记 71
粉丝 8
获赞 17

Java中Record类型是Java 14中的预览函数引入的,并且应作为普通的 不可变 数据类,用于在类和应用程序之间进行数据传输。

Enum 一样,Record也是一个特殊的类输入Java。它旨在用于仅创建类以充当普通数据载体的地方。

类(Class)与记录(Record)之间的重要区别是,Record旨在消除设置和从实例获取数据所需的所有代码,Record将这种责任转移给生成编译器。

我们可以在 record 定义中覆盖上面提供的任何默认方法,以实现自定义行为。

Record语法

使用关键字 record 在Java中创建此类Record类。就像我们在构造函数中所做的一样,我们需要在Record中提及属性及其类型。

在给定的示例中, EmployeeRecord 用于保存员工信息,即

package com.howtodoinjava.core.basic;

public record EmployeeRecord(Long id, 
		String firstName, 
		String lastName, 
		String email, 
		int age) {
	
}

Record使用

要创建一条Record,请调用其构造函数并在其中传递所有字段信息。然后,我们可以使用JVM生成的getter方法获取记录信息,并调用任何生成的方法。

package com.howtodoinjava.core.basic;

public class RecordExample {
	public static void main(String[] args) 
	{
		EmployeeRecord e1 = new EmployeeRecord
				(1l, "Lokesh", "Gupta", "howtodoinjava@gmail.com", 38);
		
		System.out.println(e1.id());
		System.out.println(e1.email());
		
		System.out.println(e1);
	}
}

程序输出:

1
howtodoinjava@gmail.com
EmployeeRecord[id=1, firstName=Lokesh, lastName=Gupta, 
			email=howtodoinjava@gmail.com, age=38]

Record查看

当我们创建 EmployeeRecord时,编译器会创建字节码,并在生成的类文件中包含以下内容:

  1. 接受所有字段的构造函数。

  2. toString()方法,用于打印Record中所有字段的状态/值。

  3. 使用基于 invokedynamic 的机制的 equals() hashCode()方法。

  4. 其名称类似于字段名称的getter方法,即 id() firstName() lastName() email() age()

  5. 扩展了java.lang.Record ,它是所有Record的基类。这意味着Record不能扩展其他类。

  6. 该类被标记为 final ,这意味着我们无法创建它的子类。

  7. 它没有任何setter方法,这意味着Record实例被设计为不可变的。

如果在生成的类文件上运行 javap 工具,我们将看到该类文件。

public final class com.howtodoinjava.core.basic.EmployeeRecord extends java.lang.Record {
  //1							
  public com.howtodoinjava.core.basic
  	.EmployeeRecord(java.lang.Long, java.lang.String, java.lang.String, java.lang.String, int);

  //2
  public java.lang.String toString();

  //3
  public final int hashCode();
  public final boolean equals(java.lang.Object);

  //4
  public java.lang.Long id();
  public java.lang.String firstName();
  public java.lang.String lastName();
  public java.lang.String email();
  public int age();
}

Record不能被继承

尽管所有Record都扩展了 java.lang.Record 类,但是我们仍然不能显式创建 java.lang.Record 的子类。编译器不会通过。

final class Data extends Record {
	private final int unit;
}

// Compiler error : The type Data may not subclass Record explicitly

这意味着获取Record的唯一方法是显式声明一个Record并让 javac 创建类文件。

Record添加注释

我们可以为Record的组件添加注释,这些注释适用于它们。例如,我们可以将 @Transient 批注应用于 id 字段。

public record EmployeeRecord(
		@Transient Long id, 
		String firstName, 
		String lastName, 
		String email, 
		int age) 
{
	//
}

Record序列

Record类的 serialVersionUID  0L ,除非它是明确声明。

Record对象序列化的过程无法自定义;Record类定义的任何特定于类的代码 writeObject,readObject,readObjectNoData,readResolve,writeExternal和readExternal方法在序列化和反序列化期间都将被忽略。但是,writeReplace方法可用于返回要序列化的替代对象。

在执行任何 序列化或反序列化之前,我们必须确保Record必须可序列化或可外部化。

import java.io.Serializable;

public record EmployeeRecord (
		Long id, 
		String firstName, 
		String lastName, 
		String email, 
		int age) implements Serializable
{

}
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class RecordExample {
	public static void main(String[] args) 
	{
		EmployeeRecord e1 = new EmployeeRecord
				(1l, "Lokesh", "Gupta", "howtodoinjava@gmail.com", 38);
		
		writeToFile(e1, "employee1");
                System.out.println(readFromFile("employee1"));
	}
	
	static void writeToFile(EmployeeRecord obj, String path) {
        try (ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream(path))){
            oos.writeObject(obj);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
	
    static EmployeeRecord readFromFile(String path) {
    	EmployeeRecord result = null;
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream(path))){
            result = (EmployeeRecord) ois.readObject();
        } catch (ClassNotFoundException | IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}

程序输出:

EmployeeRecord[id=1, firstName=Lokesh, lastName=Gupta, 
			email=howtodoinjava@gmail.com, age=38]

Record字段和方法

添加到Record中的新字段必须为Static 静态 也可以添加一种方法,该方法可以访问Record字段的内部状态。

编译器不会在隐式生成的字节码中使用添加的字段和方法,因此它们不属于任何方法实现,例如 equals() hashCode() toString()。我们必须根据需要明确使用它们

public record EmployeeRecord(
		Long id, 
		String firstName, 
		String lastName, 
		String email, 
		int age) implements Serializable 
{
	//additional field
	static boolean minor;
	
	//additional method
	public String fullName() 
	{
		return firstName + " " + lastName;
	}
}

Record构造函数

我们可以添加构造器特定代码,以在紧凑的构造器中进行数据验证。

我们不需要为字段指定构造函数参数的分配,因为它以通常的方式在规范构造函数中发生。

public record EmployeeRecord(
		Long id, 
		String firstName, 
		String lastName, 
		String email, 
		int age) implements Serializable 
{
	public EmployeeRecord
	{
		if(age < 18)
		{
			throw new IllegalArgumentException(
	                "You cannot hire a minor person as employee");
		}
	}
}


打开App,阅读手记
0人推荐
发表评论
随时随地看视频慕课网APP