MST

星途 面试题库

面试题:Java自定义对象序列化与反序列化:版本控制

假设有一个Java类`Product`,已经实现了自定义序列化与反序列化。随着项目的发展,`Product`类增加了一个新的属性`description`(字符串类型)。请说明如何在不破坏已有序列化数据的情况下,对新老版本的`Product`对象进行序列化与反序列化,详细阐述版本控制的实现思路及关键代码片段。
48.2万 热度难度
编程语言Java

知识考点

AI 面试

面试题答案

一键面试
  1. 版本控制实现思路

    • 在Java的序列化机制中,可以通过定义一个名为serialVersionUID的静态常量来进行版本控制。serialVersionUID是一个标识类的序列化形式的版本号。
    • 对于新老版本兼容性问题,在老版本中没有description属性,在反序列化时,需要确保老版本数据能够正确加载,而对于新版本对象,description属性应该能正常序列化和反序列化。
    • 当类结构发生变化(如添加新属性)时,手动指定serialVersionUID为一个固定值,这样在序列化和反序列化过程中,Java序列化机制会认为新老版本是兼容的。
  2. 关键代码片段

    • 定义Product
import java.io.*;

public class Product implements Serializable {
    // 手动指定固定的serialVersionUID,确保新老版本兼容性
    private static final long serialVersionUID = 1L;
    // 已有属性
    private String name;
    private double price;
    // 新增属性
    private String description;

    public Product(String name, double price) {
        this.name = name;
        this.price = price;
    }

    // 新增属性的getter和setter方法
    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    // 自定义序列化方法
    private void writeObject(ObjectOutputStream out) throws IOException {
        out.writeObject(name);
        out.writeDouble(price);
        // 新增属性,老版本数据没有,需要判断是否为null
        if (description != null) {
            out.writeBoolean(true);
            out.writeObject(description);
        } else {
            out.writeBoolean(false);
        }
    }

    // 自定义反序列化方法
    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        price = in.readDouble();
        boolean hasDescription = in.readBoolean();
        if (hasDescription) {
            description = (String) in.readObject();
        }
    }
}
  • 测试序列化和反序列化
import java.io.*;

public class SerializationTest {
    public static void main(String[] args) {
        // 创建新版本Product对象
        Product product = new Product("Sample Product", 10.0);
        product.setDescription("This is a sample product");

        // 序列化对象
        try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("product.ser"))) {
            oos.writeObject(product);
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 反序列化对象
        Product deserializedProduct = null;
        try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("product.ser"))) {
            deserializedProduct = (Product) ois.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }

        if (deserializedProduct != null) {
            System.out.println("Name: " + deserializedProduct.getName());
            System.out.println("Price: " + deserializedProduct.getPrice());
            System.out.println("Description: " + deserializedProduct.getDescription());
        }
    }
}

在上述代码中:

  • 通过手动设置serialVersionUID = 1L,确保新老版本兼容性。
  • writeObject方法中,对新增的description属性进行了特殊处理,在写入数据前先判断其是否为null,然后根据判断结果写入相应数据。
  • readObject方法中,按照写入的顺序读取数据,对于老版本数据没有description属性的情况也进行了妥善处理。