1. 引言

本文将探讨编程中的"水合"概念,深入解析Java对象水合的具体含义和应用场景。

2. 对象水合

2.1 延迟初始化

延迟加载或延迟初始化是软件应用中的常见模式。在Java中,对象是通过new关键字创建的类实例。对象是程序的构建块,通过与其他对象交互实现功能。

在面向对象编程中,对象通常代表现实世界实体,因此具有多个关联属性。对象初始化指用实际数据填充对象属性的过程。这通常通过调用类构造函数并传入数据参数完成,也可从网络、数据库或文件系统等数据源进行初始化

对象初始化有时是资源密集型操作,尤其当数据来自外部数据源时。此外,对象创建后并非总是立即被程序使用。

这种情况下,最佳实践是尽可能延迟对象初始化,直到真正需要时。这种模式称为延迟初始化——我们先创建空数据对象,后续再惰性填充相关数据。有意识地延迟数据初始化能提升代码性能和内存利用率

创建一个包含多个属性的User类:

public class User {
    private String uId;
    private String firstName;
    private String lastName;
    private String alias;
    // 构造函数、getter-setter
}

我们可以创建User对象并保存在内存中,而不填充其属性:

User iamUser = new User();

2.2 什么是水合?

延迟初始化中,我们刻意延迟已创建对象的初始化过程。向现有空对象填充数据的过程称为水合(Hydration)

创建的User实例是空壳对象,因当前不需要而未填充相关数据。要使对象可用,需用领域数据填充,这些数据可来自网络、数据库或文件系统

通过以下步骤实现用户实例水合。首先编写类级水合方法,使用setter设置数据:

public void generateMyUser() {
    this.setAlias("007");
    this.setFirstName("James");
    this.setLastName("Bond");
    this.setuId("JB");
}

现在创建空User实例,需要时调用generateMyUser()方法进行水合

User jamesBond = new User();
// 执行水合
jamesBond.generateMyUser();

通过断言属性状态验证水合结果:

User jamesBond = new User();
Assert.assertNull(jamesBond.getAlias());

jamesBond.generateMyUser();
Assert.assertEquals("007", jamesBond.getAlias());

3. 水合与反序列化

水合和反序列化不是同义词,不可互换使用。**反序列化是从序列化形式重建对象的过程**。我们常存储或通过网络传输对象,此时序列化(对象转字节流)和反序列化(重建对象)就派上用场。

User实例序列化到文件:

try {
    FileOutputStream fileOut = new FileOutputStream(outputName);
    ObjectOutputStream out = new ObjectOutputStream(fileOut);
    out.writeObject(user);
    out.close();
    fileOut.close();
} catch (IOException e) {
    e.printStackTrace();
}

需要时从序列化形式重建User实例:

try {
    FileInputStream fileIn = new FileInputStream(serialisedFile);
    ObjectInputStream in = new ObjectInputStream(fileIn);
    deserializedUser = (User) in.readObject();
    in.close();
    fileIn.close();
} catch (IOException | ClassNotFoundException e) {
    e.printStackTrace();
}

⚠️ 关键区别

  • 反序列化:单步完成对象创建和属性填充
  • 水合:仅向已创建对象添加数据
  • ❌ 反序列化 = 对象实例化 + 水合(一步完成)

4. ORM框架中的水合

ORM(对象关系映射)框架结合了面向对象编程与关系数据库。ORM框架实现应用对象与数据库表的映射,使开发者能以原生对象方式操作数据库实体。

对象水合在Hibernate或JPA等ORM框架中更常见。

以JPA实体类Book及其Repository为例:

@Entity
@Table(name = "books")
public class Book {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    @Column(name = "name")
    private String name;
    // 其他列和方法
}
public interface BookRepository extends JpaRepository<Book, Long> {
}

根据ORM原则,实体Book代表数据库表,实体与数据库的交互通过BookRepository接口抽象。类实例代表表中的一行。

使用内置find()方法或自定义查询加载Book实例时,ORM框架执行以下步骤:

Book aTaleOfTwoCities = bookRepository.findOne(1L);

框架执行流程

  1. ✅ 调用默认构造函数初始化空对象
  2. ✅ 尝试从缓存加载属性数据
  3. ⚠️ 缓存未命中时,连接数据库查询表
  4. ✅ 获取ResultSet后,水合对象aTaleOfTwoCities
  5. ✅ 返回最终实例

5. 总结

本文探讨了编程中水合的概念,对比了水合与反序列化的区别,并通过ORM框架和普通对象模型展示了对象水合的实际应用。

本文代码示例可在GitHub获取。


原始标题:What Does It Mean to Hydrate an Object? | Baeldung