登录
首页 >  文章 >  java教程

Java值对象与实体对象区别解析

时间:2026-05-29 20:17:55 444浏览 收藏

本文深入剖析了Java中值对象(Value Object)与实体对象(Entity)的本质区别:值对象以属性相等性定义同一性、不可变、无业务身份标识,强调概念完整性与内聚业务规则,通常嵌入实体中存在;而实体对象依靠业务主键(如userId、orderNo)唯一标识、可变、拥有独立生命周期和复杂状态管理。文章不仅厘清常见误区(如仅凭@Id注解误判实体),还结合DDD思想、JPA/MyBatis实践及代码示例,揭示二者在设计意图、实现方式与领域语义上的根本差异——帮你避开贫血模型陷阱,写出真正表达业务含义的高质量领域对象。

Java里值对象和实体对象怎么区分_Java对象建模说明

值对象没有唯一标识,实体对象有业务主键

值对象(Value Object)的核心特征是“相等性由属性决定”,只要所有字段值相同,就认为是同一个值对象;实体对象(Entity)则靠 id 或业务主键(如 orderNouserId)区分身份,即使字段全一样,id 不同就是不同实体。

常见误判点:把带 id 字段的类默认当实体——其实如果这个 id 仅用于数据库映射、不参与业务逻辑识别(比如只是 JPA 的 @Id 但业务中从不按它查/比/聚合),它仍可能是值对象。

  • 订单项 OrderItem 通常是值对象:它属于某订单,自身无独立生命周期,两个单价+数量+商品ID完全相同的项可互换
  • 用户 User 是实体:哪怕两个用户姓名电话都一样,userId 不同就必须视为不同个体
  • 金额 Money 是典型值对象:不关心“谁创建的100元”,只关心“是不是100元人民币”

值对象通常不可变,实体对象允许状态变更

值对象一旦创建,字段不应被修改(即所有字段用 final,构造函数全参数初始化),这是保证其“值语义”的基础;实体对象则天然支持状态变化,比如 User.setStatus()Order.setPaidAt()

Java 中常用方式:

  • 值对象:用 record(Java 14+)或手动写 final 字段 + 全参构造 + equals/hashCode(IDE 可自动生成)
  • 实体对象:普通 class,字段非 final,常配合 ORM 框架(如 Hibernate)管理持久化状态
  • 注意:JPA 实体类若用 record 会报错——因为 JPA 要求默认构造器和 setter,而 record 不提供
public record Money(BigDecimal amount, Currency currency) {
    public Money {
        Objects.requireNonNull(amount);
        Objects.requireNonNull(currency);
    }
}

值对象常作为实体的组成部分,不单独持久化

值对象一般不对应数据库单表,而是嵌入在实体表中,比如 address 字段存为 JSON 或拆成 address_line1city 等字段;而实体对象通常有自己对应的表,且含主键列。

JPA 中体现为:

  • @Embedded + @Embeddable 标记值对象(如 @Embeddable class Address
  • 实体类中直接声明该类型字段:@Embedded private Address address;
  • 避免给值对象加 @Entity@Table,否则 Hibernate 会尝试建表并报错
  • MyBatis 中无原生支持,需手动处理序列化(如用 TypeHandlerAddress 转为 JSON 存 varchar)

领域驱动设计(DDD)里,值对象强调概念完整性

值对象不只是“没 ID 的 POJO”,它代表一个不可分割的业务概念。比如 PhoneNumber 不应只存字符串,而应封装区号、号码、校验逻辑;Range 应包含 fromtocontains() 方法。

判断是否该建值对象的关键问题:

  • 这个概念在业务中是否总是以整体出现?(如“配送时间窗口”必须同时含开始和结束,不能只设一个)
  • 是否需要约束内部字段组合?(如 email 字段必须含 @,password 必须满足强度规则)
  • 是否会被多个实体共享且无需跟踪变更历史?(如共享的 TaxRate 配置)

实体对象的复杂度往往来自生命周期管理(创建、修改、软删、归档),而值对象的复杂度来自内聚的业务规则封装——这点容易被忽略,导致把本该是值对象的类写成贫血的 DTO。

到这里,我们也就讲完了《Java值对象与实体对象区别解析》的内容了。个人认为,基础知识的学习和巩固,是为了更好的将其运用到项目中,欢迎关注golang学习网公众号,带你了解更多关于的知识点!

资料下载
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>