Java高手速成 | 新增类Record的工作实例

news2024/12/26 21:33:59

01、什么是Record?

Record 是Java新增的库类,在Java 14和Java 15中以预览(preview)形式公布。Record类用来自动生成对定义数据进行创建、设置、访问以及比较等代码,所以又被称作数据类(data class)。在一些编程语言中,例如Kotlin,已经使用数据类来处理数据模式建立(Object Relational Mapping-ORM)以及传输(Data Transfer Objects-DTOs)等处理。Record类似于Java 的枚举类(Enum),用来简化、定义和处理数据。传统的枚举类的编程方式和自动生成代码的Record类,这两者使得Java编程在保持简单性和灵活性中相互平衡和补充。

02、为什么支持Record?

在应用软件开发中,编程人员经常会针对底层数据,进行对数据的构造器、访问方法(getters)、覆盖方法equals、覆盖方法hashCode、以及覆盖方法toString进行基础和重复性的编程。而使用Record类,程序中则可省去这些代码,而由支持Record的编译器自动生成。这不但提高了编程效率,而且提高了代码的可靠性。Record类也可以提高数据在ORM和DTOs的一致性(persistency)要求。例如,使用private对数据的定义更加安全和规范化;自动生成的equals方法更加标准化和可靠;对生成的数据类定义为final,因而限制对创建后的数据类的继承以及对已定义数据的修改等等。这些特性无疑提高了代码的标准化,使得对数据类的编程更加高效和可靠。

 

03、Record编程举例

例1. 利用Record创建一个名为Circle的数据类,产生对其半径radius进行基本处理功能。如同Java的任何类一样,Record从Object类继承而来:

java.lang.Object
java.lang.Record

Record类提供一个特殊的构造器:

protected Record()

利用Record创建数据类时,其参数可以是任何类型、以及任何数目的数据。先讨论一个简单例子,如:

record Circle(double radius) {} ; //创建并自动生成Circle构造器以及相关方法代码

对以上代码编译后,将自动生成如下代码并将生成的Circle类定义为final,即我们不能用它来继承子类,也不可以修改数据radius的值:

private final double radius = 0.0;    //定义数据

    public Circle(double radius) {      //创建构造器
        this.radius = radius;
}
public double radius() {            //创建访问方法
    return radius;
}

@Override
public boolean equals(Object obj) {    //覆盖equals方法
        if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass())
      return false;
    circle = (Circle) obj;
if (radius != circle.radius())
      return false;
    else 
        return true; 
}

@Override
public int hashCode() {            //覆盖哈西方法
    return Objects.hash(radius);    //返回哈西代码
}

@Override
public String toString() {        //覆盖toString方法
    return “Circle [radius= “ + radius + “]”;
}

 以上代码都是编译器自动生成的。在应用中我们可以直接调用这些方法,如:

package Example;

public class CircleApp {

    public static void main(String[] args) {

        @SuppressWarnings("preview")

        record Circle(double radius) {};

        Circle circle = new Circle(2.345);

        System.out.println(circle.radius());

        Circle circle2 = new Circle(3.33);      //创建对象 

        System.out.println(circle.equals(circle2));     //false
        System.out.println(circle.hashCode());      //显示哈西代码 
        System.out.println(circle);         //Circle [radius=2.345]
    }
}

 以上利用Record创建Circle类的具体代码和运行结果见图1所示。

▍图1.  在Eclipse中运行Record创建的Circle类以及运行结果

例2. 利用Record创建一个名为Person的类。Person包括两个数据类,具有数据name以及ID的Student类和具有name和credit的Teacher类。并调用自动生成的方法进行测试。Person类的代码如下:

@SuppressWarnings("preview")
record Student(String name, String ID) {}; //定义数据类Student

@SuppressWarnings("preview")
record Teacher(String name, int credit) {};//定义数据类Teacher

对以上定义数据类Student和Teacher的代码编译后,将自动生成如下构造器和方法的代码:

Student类:

@SuppressWarnings("preview")
record Student(String name, String ID) {}; //定义数据类Student

@SuppressWarnings("preview")
record Teacher(String name, int credit) {};//定义数据类Teacher

 

对以上定义数据类Student和Teacher的代码编译后,将自动生成如下构造器和方法的代码:

Student类:

private final String name = null;                定义数据
private final String ID = null;

public Student (String name, String ID);            //创建构造器
public String name();                    //创建方法
public String ID();
public blooean equals(Object obj);                //覆盖equals方法
public int hashCode()                    //覆盖哈西方法
public String toString();                    //覆盖toString方法

Teacher类:

private final String name = null;                定义数据
private final int credit = 0;

public Teacher (String name, int credit);            //构造器
public String name();                    //访问方法
public int credit();
public blooean equals(Object obj);                //覆盖equals方法
public int hashCode()                    //覆盖哈西方法
public String toString();                    //覆盖toString方法

值得指出的是,由于Student和Teacher各自都有有两个数据,在Student中覆盖后的equals方法代码如下:

@Override
public boolean equals(Object obj) {                //覆盖equals方法
        if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass())
        return false;
    person = (Person) obj;
return (name.compareTo(person.name()) && ID.compareTo(person.ID()
&& ID.compareTo(person.ID()); 
}

在Teacher中覆盖后的equals方法代码如下:

@Override
public boolean equals(Object obj) {                //覆盖equals方法
        if (this == obj) return true;
    if (obj == null || getClass() != obj.getClass())
        return false;
    person = (Person) obj;
return (name.compareTo(person.name()) && (credit
== person.credit()); 
}

以上利用Record创建数据类Student和Teacher以及其测试程序如图2所示。

▍图2. 在Eclipse中运行record创建的数据类

这个程序的运行结果如下:

Wang Lin
112233
false
-2104304052
Student[name=Li Gong, ID=445566]
Name = Dr. Zhang, credit = 10, Count = 0
Name = Mr. Qian, credit = 8, Count = 0
1
2
-793483106
-1753498516
false
Teacher[name=Mr. Qian, credit=8]

04、可以在Record创建数据类时加入其他代码吗?

我们只可以增添静态数据和静态方法以及对数据的访问方法。以Circle2为例:

@SuppressWarnings("preview")
record Circle2(double radius) {
        static int count;               //加入静态数据

        public static void doCount() {      //加入静态方法
            count++;
        }  

        public static int getCount() {      //静态数据访问方法
            return count;
        }
        public String getDiameter() {       //加入对数的访问方法
            return "Diameter = " + radius *2;
        }
}

以上扩充或修改不会影响Record对Circle2的创建和自动生成的各个方法。其测试程序和运行结果截图如图3所示:

▍图3. 在Eclipse中运行record创建的数据类Circle2

05、解析Java编译器对创建数据类产生的代码(提高篇)

在操作系统中利用Java编译指令javap可以观察编译器在创建数据类时产生的详细代码描述和规范清单。这个代码清单用可能超出我们对Java应用程序的编程范围,这里只是给读者提供一个概况性的解释。

我们以例1中讨论过的Circle为例,在操作系统中进入储存Circl的目录,打入如下编译指令:

javac --enable-preview --release 15 Circle.java

编译器将显示如下提示信息:

Note: Circle.java uses preview language features.
Note: Recompile with -Xlint:preview for details.

表示正在使用Java的预览特性编译代码。再打入如下执行指令:

javap -v -p Circle.class

如图4所示。

▍图4.  在操作系统中打入指定的javac指令编译预览库类

产生java编译器生成的文件Circle.class后,打入:

javap -v -p Circle.class

这个指令将显示JVM生成的对数据类Circle的详细代码规范清单,如下所示:

C:\Users\ygao\eclipse-workspace\myProject\src\example>javap -v -p Circle.class
Classfile /C:/Users/ygao/eclipse-workspace/myProject/src/example/Circle.class
  Last modified Jan 5, 2021; size 1096 bytes
  MD5 checksum a7717f26f0812dac23eb89a37ccbc91d
  Compiled from "Circle.java"
final class example.Circle extends java.lang.Record
  minor version: 65535
  major version: 59
  flags: (0x0030) ACC_FINAL, ACC_SUPER
  this_class: #8                          // example/Circle
  super_class: #2                         // java/lang/Record
  interfaces: 0, fields: 1, methods: 5, attributes: 4
Constant pool:
   #1 = Methodref          #2.#3          // java/lang/Record."<init>":()V
   #2 = Class              #4             // java/lang/Record
   #3 = NameAndType        #5:#6          // "<init>":()V
   #4 = Utf8               java/lang/Record
   #5 = Utf8               <init>
   #6 = Utf8               ()V
   #7 = Fieldref           #8.#9          // example/Circle.radius:D
   #8 = Class              #10            // example/Circle
   #9 = NameAndType        #11:#12        // radius:D
  #10 = Utf8               example/Circle
  #11 = Utf8               radius
  #12 = Utf8               D
  #13 = InvokeDynamic      #0:#14         // #0:toString:(Lexample/Circle;)Ljava/lang/String;
  #14 = NameAndType        #15:#16        // toString:(Lexample/Circle;)Ljava/lang/String;
  #15 = Utf8               toString
  #16 = Utf8               (Lexample/Circle;)Ljava/lang/String;
  #17 = InvokeDynamic      #0:#18         // #0:hashCode:(Lexample/Circle;)I
  #18 = NameAndType        #19:#20        // hashCode:(Lexample/Circle;)I
  #19 = Utf8               hashCode
  #20 = Utf8               (Lexample/Circle;)I
  #21 = InvokeDynamic      #0:#22         // #0:equals:(Lexample/Circle;Ljava/lang/Object;)Z
  #22 = NameAndType        #23:#24        // equals:(Lexample/Circle;Ljava/lang/Object;)Z
  #23 = Utf8               equals
  #24 = Utf8               (Lexample/Circle;Ljava/lang/Object;)Z
  #25 = Utf8               (D)V
  #26 = Utf8               Code
  #27 = Utf8               LineNumberTable
  #28 = Utf8               MethodParameters
  #29 = Utf8               ()Ljava/lang/String;
  #30 = Utf8               ()I
  #31 = Utf8               (Ljava/lang/Object;)Z
  #32 = Utf8               ()D
  #33 = Utf8               SourceFile
  #34 = Utf8               Circle.java
  #35 = Utf8               Record
  #36 = Utf8               BootstrapMethods
  #37 = MethodHandle       6:#38          // REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
  #38 = Methodref          #39.#40        // java/lang/runtime/ObjectMethods.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
  #39 = Class              #41            // java/lang/runtime/ObjectMethods
  #40 = NameAndType        #42:#43        // bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
  #41 = Utf8               java/lang/runtime/ObjectMethods
  #42 = Utf8               bootstrap
  #43 = Utf8               (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
  #44 = String             #11            // radius
  #45 = MethodHandle       1:#7           // REF_getField example/Circle.radius:D
  #46 = Utf8               InnerClasses
  #47 = Class              #48            // java/lang/invoke/MethodHandles$Lookup
  #48 = Utf8               java/lang/invoke/MethodHandles$Lookup
  #49 = Class              #50            // java/lang/invoke/MethodHandles
  #50 = Utf8               java/lang/invoke/MethodHandles
  #51 = Utf8               Lookup
{
  private final double radius;
    descriptor: D
    flags: (0x0012) ACC_PRIVATE, ACC_FINAL

  example.Circle(double);
    descriptor: (D)V
    flags: (0x0000)
    Code:
      stack=3, locals=3, args_size=2
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Record."<init>":()V
         4: aload_0
         5: dload_1
         6: putfield      #7                  // Field radius:D
         9: return
      LineNumberTable:
        line 4: 0
    MethodParameters:
      Name                           Flags
      radius

  public final java.lang.String toString();
    descriptor: ()Ljava/lang/String;
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokedynamic #13,  0             // InvokeDynamic #0:toString:(Lexample/Circle;)Ljava/lang/String;
         6: areturn
      LineNumberTable:
        line 3: 0

  public final int hashCode();
    descriptor: ()I
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokedynamic #17,  0             // InvokeDynamic #0:hashCode:(Lexample/Circle;)I
         6: ireturn
      LineNumberTable:
        line 3: 0

  public final boolean equals(java.lang.Object);
    descriptor: (Ljava/lang/Object;)Z
    flags: (0x0011) ACC_PUBLIC, ACC_FINAL
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0
         1: aload_1
         2: invokedynamic #21,  0             // InvokeDynamic #0:equals:(Lexample/Circle;Ljava/lang/Object;)Z
         7: ireturn
      LineNumberTable:
        line 3: 0

  public double radius();
    descriptor: ()D
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: getfield      #7                  // Field radius:D
         4: dreturn
      LineNumberTable:
        line 3: 0
}
SourceFile: "Circle.java"
Error: unknown attribute
  Record: length = 0x8
   00 01 00 0B 00 0C 00 00
BootstrapMethods:
  0: #37 REF_invokeStatic java/lang/runtime/ObjectMethods.bootstrap:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/TypeDescriptor;Ljava/lang/Class;Ljava/lang/String;[Ljava/lang/invoke/MethodHandle;)Ljava/lang/Object;
    Method arguments:
      #8 example/Circle
      #44 radius
      #45 REF_getField example/Circle.radius:D
InnerClasses:
  public static final #51= #47 of #49;    // Lookup=class java/lang/invoke/MethodHandles

总结一下这个代码清单告诉我们的有关Circle类规范化信息:

1. 正如我们讨论过的,Circle被定义为final,所以我们不能修改它的数据,也不能改变自动生成的方法以及不能继承子类。

2. 它从java.lang.Record继承而来。它具有一个数据,5个方法以及4个参数(attributes)。

数据:private final double radius;初始化值为0.0。

方法:public final String toString()、public final int hashCode()、public final boolean equals(Object)、 public final double radius()以及构造器public Circle(double)。

3. 这些方法由方法处理器(Method Handles)在调用时激活和援引(Invoke Dynamic)。

4. 一个启动方法ObjectMethod.bootstrap利用数据类中的数据名如radius和访问方法,如radius()来产生其他各个方法, 如toString, hashCode(), equals()以及Circle(double)。

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/154734.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

初级开发者福音:手把手教你实现数字滚动效果~

文章目录一、前言二、背景知识三、实现方案Step 1&#xff1a;分析需求Step 2&#xff1a;实现单个数字的滚动效果Step 3&#xff1a;组件接口设计Step 4&#xff1a;完善组件一、前言 前端数字滚动显示的场景很多&#xff0c;比如抽奖的时候&#xff0c;营造一种马上公布中奖…

[MySQL从入门到实战环境部署](超详细版)

MySQL从入门到实战环境部署1.部署CentOS1.1部署CenOS虚拟机步骤&#xff08;1&#xff09;基于VirtualBox&#xff08;2&#xff09;下载CentOS1.2环境部署过程2.部署MySQL1.部署CentOS 1.1部署CenOS虚拟机步骤 &#xff08;1&#xff09;基于VirtualBox 下载网址&#xff1…

Docker Compose:Docker Compose部署nacos初始化MySQL

Docker Compose&#xff1a;Docker Compose部署nacos初始化MySQL找初始化sql文件nacos初始化mysql-schema.sql文件内容docker-compose.yml上传到挂载目录运行docker-compose.yml访问nacos找初始化sql文件 先去官网下载nacos安装包 官方github地址&#xff1a;https://github.…

Centos7安装opengauss

安装包下载地址&#xff1a;https://www.opengauss.org/zh/download/注&#xff1a;本文介绍的是轻量版安装先创建一个系统用户&#xff08;opengauss数据库不允许使用 root 用户安装&#xff09;创建用户useradd omm设置密码passwd omm将安装包拷贝并解压到用户家目录 ~/openG…

linux-云服务器数据盘挂载失败导致进入维护模式

已经在华为云、AWS上面吃过这个亏了&#xff0c;老这样可不好&#xff0c;心怦怦跳的。 华为云是由于服务器升级配置后重启&#xff0c;数据盘名称变化导致进入维护模式。AWS则是由于重启后没有挂载上数据盘&#xff0c;手动编辑/etc/fstab文件错误导致进入维护模式。 究其原…

2022年航空发动机行业研究报告

第一章 行业概况 航空发动机制造指主要用来产生拉力或推力使飞机前进的发动机设备。除了产生前进力外&#xff0c;还可以为飞机上的用电设备提供电力&#xff0c;为空调设备等用气设备提供气源。航空发动机制造产业链包括原材料研发、零部件生产制造、分系统和整机制造。 原材…

大智慧同花顺Level2行情数据有什么用

股市L2是大智慧Level2数据。由“上海证券交易所”最新推出的实时行情信息收费服务&#xff0c;主要提供在上海证券交易所上市交易的证券产品的实时交易数据。该行情速度比传统行情快3秒以上&#xff0c;同时包括十档行情、买卖队列、逐笔成交、总买总卖和统计信息等多种新式数据…

Fabric.js 拖放元素进画布

本文简介 点赞 关注 收藏 学会了 学习 Fabric.js&#xff0c;我的建议是看文档不如看 demo。 本文实现的功能&#xff1a;将元素拖进到画布中并生成对应的图形或图片。 效果如下图所示&#xff1a; 思路 要实现以上效果&#xff0c;需要考虑以下几点&#xff1a; 元素有…

婴儿游泳池行业市场经营管理及未来前景展望分析

2023-2029年中国婴儿游泳池行业市场经营管理及未来前景展望报告报告编号&#xff1a;1691316免费目录下载&#xff1a;http://www.cninfo360.com/yjbg/qthy/ly/20230109/1691316.html本报告著作权归博研咨询所有&#xff0c;未经书面许可&#xff0c;任何组织和个人不得以任何形…

PyQt6快速入门-事件处理

事件处理 文章目录 事件处理1、Qt事件介绍2、常用事件函数2.1 paintEvent事件2.2 鼠标事件2.3 窗口大小改变事件2.4 窗口隐藏/关闭/显示事件2.5 键盘按键事件3、事件拦截4、事件过滤器5、事件队列与事件处理1、Qt事件介绍 Qt GUI应用程序的核心是 QApplication 类。 每个GUI应…

Linux 文件 I/O

1.Linux 应用编程中最基础的知识&#xff0c;即文件 I/O&#xff08;Input、 Outout&#xff09; &#xff0c; 文件 I/O 指的是对文件的输入/输出操作&#xff0c;说白了就是对文件的读写操作&#xff1b; Linux 下一切皆文件&#xff0c;文件作为 Linux 系统设计思想的核心理…

java Lambda表达式引用类方法

Lambda表达式和方法引用是一对孪生兄弟 而引用类方法是Lambda支持的方法引用中的一种 引用类方法其实就是引用类的静态方法 直接上代码 首先 我们要创建一个包 包下创建一个接口 我这里叫subInterface 参考代码如下 public interface subInterface {int convelutl(String s…

【RabbitMQ】SpringBoot整合RabbitMQ

文章目录搭建初始环境引入依赖配置配置文件HelloWorld模型使用Work模型使用Fanout 广播模型Route 路由模型Topic 订阅模型(动态路由模型)搭建初始环境 引入依赖 <!--引入与rabbitmq集成依赖--> <dependency><groupId>org.springframework.boot</groupId…

NKOJ P3549 可见的点

分析 这道题乍一看是一道几何,实际上,是一道法雷数列模板题; 首先,他让我们求有多少条可见的线,实际上是让我们求有多少种不同的斜率可以存在,而斜率就是表现为yx\Large\frac{y}{x}xy​的形式;可以发现,只有当yx\Large\frac{y}{x}xy​为最简分数时,才能算作一条可见的线,其他…

Linux中如何使用Htop监控工具?【网络安全】

一、Htop界面展示 “Htop是一个用于Linux/Unix系统的交互式实时进程监控应用程序&#xff0c;也是top命令的替代品&#xff0c;它是所有Linux操作系统上预装的默认进程监控工具。 Htop还有许多其他用户友好的功能&#xff0c;这些功能在top命令下不可用 在Htop中&#xff0c;…

蓝桥杯省赛习题练习(二)

题目来源&#xff1a;2020年真题题集&#xff08;B组&#xff09; 注&#xff1a;代码都是自己写的&#xff0c;不是参考答案&#xff01; 目录1. 门牌制作运行结果2. 既约分数运行结果3. 蛇形填数运行结果4. 跑步锻炼运行结果5. 7段码6. 成绩统计运行结果7. 回文日期1. 门牌制…

5.9、TCP报文段的首部格式

为了实现可靠传输&#xff0c;TCP 采用了面向字节流\color{red}面向字节流面向字节流的方式。 但 TCP 在发送数据时&#xff0c;是从发送缓存取出一部分或全部字节并给其添加一个首部使之成为 TCP报文段\color{red}\texttt{TCP} 报文段TCP报文段后进行发送。 一个 TCP 报文段由…

ELAN设计理念:通过梯度路径分析设计网络设计策略

设计高效、高质量的表达性网络架构一直是深度学习领域最重要的研究课题。当今的大多数网络设计策略都集中于如何集成从不同层提取的特征&#xff0c;以及如何设计计算单元来有效地提取这些特征&#xff0c;从而增强网络的表现力。本文提出了一种新的网络设计策略&#xff0c;即…

Django框架MVT模型工作流程

Django 一、Django介绍 Django是一个开源的Web应用框架&#xff0c;由Python写成。采用了MTV的框架模式&#xff0c;它最初是被用来做CMS&#xff08;内容管理系统&#xff09;软件。 使用Django&#xff0c;程序员可以方便、快捷地创建高品质、易维护、数据库驱动的应用程序…

聚威新材在科创板被暂缓审议:毛利率高于同行,张天荣为董事长

2023年1月10日&#xff0c;上海证券交易所披露的信息显示&#xff0c;上海聚威新材料股份有限公司&#xff08;下称“聚威新材”&#xff09;被科创板上市委员会暂缓审议。据贝多财经了解&#xff0c;聚威新材仍有多个问题需进一步落实事项。 上市委要求聚威新材落实&#xff1…