You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java依赖对象序列化一致性问题:反序列化后Address引用ID不同

问题分析与解决方案

你遇到的断言失败问题,核心原因不是序列化逻辑本身的问题,而是默认的equals()方法行为和你对“相等”的预期不匹配,再加上两个类的serialVersionUID设置错误,我们一步步来解决:

1. 为什么对象ID变化是正常的?

反序列化的本质是在内存中创建一个全新的对象实例,把序列化时保存的属性值填充进去,所以反序列化后的对象内存地址(就是你看到的Address@6b143ee9这种)必然和原对象不同——这是正常现象,不用纠结这个ID的变化,真正要关注的是对象的属性值是否一致,而这需要通过正确的equals()方法来判断。

2. 断言失败的核心原因:未重写equals()和hashCode()

Java默认的Object.equals()方法是比较对象的引用地址,反序列化出来的是新对象,引用地址和原对象不一样,所以Assert.assertEquals(employee, deserialized1)必然失败。你需要为Employee和Address类重写equals()和hashCode()方法,让它们基于属性值来判断相等性。

3. 额外问题:错误的serialVersionUID设置

你给Employee和Address设置了完全相同的serialVersionUID,这是不正确的。每个可序列化类都应该有自己唯一的serialVersionUID,这个值用来验证序列化和反序列化时类结构的一致性,如果后续修改类结构(比如新增字段),只要UID不变,反序列化仍能兼容(前提是符合序列化规则)。

小笔误修正

你的测试代码里有个小问题:employee.setAddress(addressList)应该是employee.setAddresses(addressList),因为Employee类的字段是private List<Address> addresses,确保setter方法名和字段对应,否则序列化的对象属性会是空,也可能导致断言失败。


修改后的代码示例

重写Address类的equals()和hashCode()

import java.io.Serializable;
import java.util.Objects;

public class Address implements Serializable {
    // 改为类专属的唯一serialVersionUID
    private static final long serialVersionUID = 123456789L;
    private String pincode;
    private String area;
    private String state;

    // 构造器、getter、setter方法省略

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Address address = (Address) o;
        return Objects.equals(pincode, address.pincode) &&
                Objects.equals(area, address.area) &&
                Objects.equals(state, address.state);
    }

    @Override
    public int hashCode() {
        return Objects.hash(pincode, area, state);
    }
}

重写Employee类的equals()和hashCode()

import java.io.Serializable;
import java.util.List;
import java.util.Objects;

public class Employee implements Serializable {
    // 改为类专属的唯一serialVersionUID
    private static final long serialVersionUID = 987654321L;
    private Long id;
    private List<Address> addresses;
    private String name;

    // 构造器、getter、setter方法省略

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Employee employee = (Employee) o;
        return Objects.equals(id, employee.id) &&
                Objects.equals(addresses, employee.addresses) &&
                Objects.equals(name, employee.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(id, addresses, name);
    }
}

确保序列化/反序列化方法正确

你的测试中用到的serialize和deserialize方法,要确保是用标准的ObjectOutputStream和ObjectInputStream实现的,比如:

private byte[] serialize(Object obj) throws IOException {
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try (ObjectOutputStream oos = new ObjectOutputStream(bos)) {
        oos.writeObject(obj);
    }
    return bos.toByteArray();
}

private Object deserialize(byte[] data) throws IOException, ClassNotFoundException {
    ByteArrayInputStream bis = new ByteArrayInputStream(data);
    try (ObjectInputStream ois = new ObjectInputStream(bis)) {
        return ois.readObject();
    }
}

验证修改后的效果

做完以上修改后,再运行testConsistency测试,断言就会通过——因为现在equals()方法会比较两个对象的属性值是否一致,而不是比较引用地址。

内容的提问来源于stack exchange,提问作者Gaurav Sinha

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 09:04:11