Java中record与普通类的hashCode()和equals()默认实现差异疑问
Java record与普通类的equals()、hashCode()默认行为差异及设计逻辑
测试代码
public class EqualsAndHashcode { public static void main(String[] args) { var employeeA = new Employee(101); var employeeB = new Employee(101); var employeeAClass = new EmployeeClass(102); var employeeBClass = new EmployeeClass(102); var printStream = System.out; printStream.println("record equals: " + employeeA.equals(employeeB) + "\nhashcode objA: " + employeeA.hashCode() + "\nhashcode objB: " + employeeB.hashCode()); printStream.println("\nclass equals: " + employeeAClass.equals(employeeBClass) + "\nhashcode objA: " + employeeAClass.hashCode() + "\nhashcode objB: " + employeeBClass.hashCode()); } } record Employee(int empId) { } class EmployeeClass { int empId; EmployeeClass(int empId) { this.empId = empId; } }
运行结果
record equals: true hashcode objA: 101 hashcode objB: 101 class equals: false hashcode objA: 935044096 hashcode objB: 396180261
1. equals()与hashCode()默认实现差异及结果原因
- 普通类的默认实现:Java所有普通类默认继承
Object类,Object的equals()默认是引用相等比较,仅判断两个对象是否指向堆内存中的同一个地址;hashCode()默认根据对象的内存地址生成数值。测试中两个EmployeeClass实例虽然empId取值相同,但属于两个独立的对象,内存地址不同,因此equals()返回false,hashCode值也完全不同,和运行结果一致。 - record的默认实现:record是Java 16正式引入的不可变数据载体类,编译器会自动根据声明的所有成员变量,生成对应的
equals()和hashCode()逻辑:equals()会逐一比较所有成员变量的取值是否全部相等,hashCode()会基于所有成员变量的取值统一计算生成。测试中的Employee是仅包含empId一个成员的record,两个实例的empId均为101,因此equals()返回true,hashCode计算结果也完全相同。
2. 设计目的与适用场景
设计目的
此前Java开发纯数据存储类时,需要手动编写构造方法、getter、equals、hashCode、toString等模板代码,要么增加冗余工作量,要么依赖Lombok等第三方工具实现。record的设计就是为了原生支持纯数据载体类的开发,默认行为完全贴合数据类的核心诉求:以取值相等作为对象相等的判断标准,而非引用相等,大幅减少模板代码量。
优势场景
- DTO(数据传输对象):比如接口请求/响应参数封装、数据库查询结果映射,这类对象仅需要存储数据、不需要额外业务逻辑,用record可以省掉大量模板代码
- 哈希集合元素:需要放到
HashSet、作为HashMap的key的场景,record默认的equals和hashCode实现完全符合哈希集合的要求,不需要手动重写即可正常工作 - 方法多返回值封装:当方法需要返回多个关联值时,用record临时封装比
Object[]、Map的类型安全性更高,代码可读性也更强
内容的提问来源于stack exchange,提问作者San
相关产品推荐
相关产品推荐

