编程Java开发者

什么是Java中的record类,它的目的是什么,以及它有哪些限制?

用 Hintsage AI 助手通过面试

回答。

问题的历史:

Record类(record)在Java 14中作为预览功能出现,从Java 16版本开始,这是一个稳定的功能。它们实现了用于存储数据的不可变(immutable)容器的概念,类似于值对象(value-objects)。这是对Java中经典DTO和POJO冗长的反应。

问题:

对于简单的数据对象,必须手动实现构造函数、equals()、hashCode()、toString()。这是一项繁琐且容易出错的工作,需占用大量代码行。

解决方案:

Record类只需一行声明,并自动获得构造函数、getter、equals()、hashCode()、toString()。record的字段是不可变的(final),record尤其适合在应用程序的不同层之间传递信息。

代码示例:

public record Point(int x, int y) {} Point p = new Point(3, 5); System.out.println(p.x()); // 3 System.out.println(p); // Point[x=3, y=5]

主要特点:

  • 不可变性:字段为final,只能通过构造函数设置值。
  • 自动生成标准方法。
  • 不能从其他类(除了Object)继承;可以实现接口。

具有挑战性的问题。

是否可以在创建record后更改对象的状态?

不可以——所有字段都是final,无法以任何方式更改值。

是否可以在构造函数中创建具有非标准逻辑的record?

可以,您可以定义紧凑或普通构造函数并添加检查:

public record Point(int x, int y) { public Point { if (x < 0 || y < 0) throw new IllegalArgumentException(); } } }

record是否可以是抽象的,或者继承其他类的字段/逻辑?

不可以——record总是final。可以实现接口,但不能继承类,除了Object。

常见错误和反模式

  • 试图使字段可变——语法不允许。
  • 在record内部创建复杂逻辑,违反简单“数据容器”的概念。
  • 在需要普通具有行为的类的地方使用record。

生活中的例子

负面案例

为每个请求/响应使用长POJO,手动编写equals、hashCode、toString、构造函数和getter。

优点:

  • 完全的实现灵活性。

缺点:

  • 代码量大。
  • 高风险可能出现错误。

正面案例

将所有DTO转换为record类:

public record UserDTO(String login, String email) {}

优点:

  • 代码量最小。
  • 自动正确的equals/hashCode。
  • 实现错误的可能性小。

缺点:

  • 如果需要可变对象或特定逻辑,record将不适合。