Serializable:readResolve

本文详细解释了序列化类中readResolve()方法的作用,当该方法被调用时,序列化过程会直接返回readResolve()方法返回的对象,而忽略readObject的实现。并通过实例代码演示了这一特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

如果序列化类定义了Object readResolve() ,那么将无视readObject的实现,直接返回作为readResolve() 方法返回值的对象。

public class People implements Serializable
{
    /**
     * 
     */
    private static final long serialVersionUID = 2659082826995480601L;
    private int age;
    private String name;

    People(int age,String name)
    {
        this.age = age;
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    private void writeObject(ObjectOutputStream out)
    {
        System.out.println("是否调用了我?");
    }
    private void readObject(ObjectInputStream in)
    {
        System.out.println("是否调用了我?");
    }

    private Object readResolve() 
    {
        return new People(20,"老子喜欢刚正面");
    }

}

测试程序:

@Test
public void testOut01() throws FileNotFoundException, IOException
{
    People p = new People(100,"老汉");
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("D:\\temp01.txt"));
    out.writeObject(p);
    out.flush();
    out.close();
}

@Test
public void testIn01() throws FileNotFoundException, IOException, ClassNotFoundException
{
    ObjectInputStream in = new ObjectInputStream(new FileInputStream("D:\\temp01.txt"));
    People p = (People)in.readObject();
    in.close();
    System.out.println(p.getAge());
    System.out.println(p.getName());

}

People p = (People)in.readObject();拿到了

private Object readResolve() 
{
    return new People(20,"老子喜欢刚正面");
}

这个对象,尽管writeObject/readObject什么都没做。
在这个过程中writeObject/readObject仍然在序列话和反序列化过程中被调用。

### Serializable 接口中的 `serialVersionUID` 的作用 在 Java 中,当对象被序列化时,Java 虚拟机会为其分配一个默认的版本号,称为 `serialVersionUID`。这个编号用于验证反序列化的类定义是否与原始序列化数据匹配。如果两者不一致,则会抛出 `InvalidClassException` 异常。 #### 自动生成 vs 手动指定 `serialVersionUID` 如果没有显式声明 `serialVersionUID`,编译器会在运行时基于类的各种属性自动生成该值[^1]。然而,这种自动计算的方式可能会因为细微的变化(如字段顺序调整、方法签名修改等)而导致不同的 `serialVersionUID` 值,从而引发兼容性问题。因此,推荐手动设置 `serialVersionUID` 来确保一致性。 以下是正确设置 `serialVersionUID` 的方式: ```java public class MyClass implements java.io.Serializable { private static final long serialVersionUID = 1L; // 类成员和其他逻辑... } ``` 通过这种方式,即使未来对类进行了某些不影响其核心功能的小改动,只要保持 `serialVersionUID` 不变,仍然可以成功完成序列化和反序列化操作。 #### 设置 `serialVersionUID` 的最佳实践 为了提高应用程序性能并减少潜在错误风险,在实现 `Serializable` 接口时应遵循以下建议: - **始终定义静态最终变量**:将 `serialVersionUID` 定义为 `private static final long` 类型,并赋予唯一标识符。 - **考虑向后兼容性需求**:设计初期就规划好可能发生的变更及其影响范围,合理设定初始值以便后续扩展时不破坏现有结构[^3]。 - **利用工具辅助生成**:IDE 如 Eclipse 或 IntelliJ IDEA 提供了便捷的功能来帮助开发者快速创建合适的 `serialVersionUID` 数字串[^4]。 下面是一个完整的例子展示如何在一个单例模式下的可序列化类里应用这些原则: ```java public class SingletonClass implements java.io.Serializable { private static final long serialVersionUID = 7890123456789012345L; private static volatile SingletonClass instance; private SingletonClass(){} public static SingletonClass getInstance(){ if(instance == null){ synchronized(SingletonClass.class){ if(instance==null){ instance=new SingletonClass(); } } } return instance; } // 防止反序列化时创建新实例 protected Object readResolve() throws java.io.ObjectStreamException{ return getInstance(); } } ``` 此代码片段不仅实现了基本的线程安全单例模式,还包含了防止非法反射攻击以及控制序列化行为的部分。 ### 结论 综上所述,理解并恰当地运用 `serialVersionUID` 是掌握 Java 序列化机制的重要一环。它不仅能增强程序稳定性还能简化维护过程。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值