序列化和反序列化

序列化和反序列化

  1. 序列化:将对象变成二进制保存在文件或者数据库中。
  2. 反序列化:将文件中或数据库中的二进制文件变成一个对象。

对象序列化的两种用途:

  1. **对象持久化:**把对象的字节序列永久地保存到硬盘上。
  2. **网络传输对象:**数据是以二进制序列的形式在网络上进行传输的。所以发送方需要把对象转换成字节序列,才能在网络上传送;接收方 则需要把字节序列再恢复成对象。

举例:

Web 服务器中的 Session 会话对象,当有10万用户并发访问,就有可能出现10万个 Session 对象,显然这种情况内存可能是吃不消 的,于是Web 容器就会把一些 Session 先序列化,让他们离开内存空间,序列化到硬盘中,当需要调用时,再把保存在硬盘中的对象还原到内存中。

序列化实例

在Java中,如果一个对象要实现能够反序列或者反序列化,就必须实现Serializable接口,这是个标记接口,里面没有什么方法。

@Data
public class Data implements Serializable {

    private static final String DATA_FILE = "DataTest.txt";
    // 静态变量,不会参与序列化
    public static String one= "1";
    // transient变量,没有序列化
    public transient String tow;
    // 普通的实例常量,可以序列化
    private int n;
    private String msg;

    public Data(String tow, int n, String msg) {
        this.tow = tow;
        this.n = n;
        this.msg = msg;
    }
  
   /**
     * 序列化
     * @throws FileNotFoundException
     * @throws IOException
     */
    public  void serialize() throws FileNotFoundException, IOException {
        System.out.println("序列化前静态变量:"+Data.one );
        System.out.println("序列化前对象:"+this);
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(DATA_FILE));
        oos.writeObject(this);
        oos.close();
    }

    /**
     * 反序列化
     * @throws FileNotFoundException
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public static void deserialize() throws FileNotFoundException, IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(DATA_FILE));
        Data data = (Data) ois.readObject();
        System.out.println( "反序列化后静态变量:"+Data.one);
        System.out.println("反序列化后对象:"+data);
        ois.close();
    }
}

测试序列化

 public static void main(String[] args)
            throws FileNotFoundException, ClassNotFoundException, IOException {
        Data data = new Data("2",123, "data-serialization");
        Data.one="1024";
        System.out.println("--------------序列化开始----------------");
        data.serialize();
        System.out.println("--------------序列化结束----------------");
    }

运行结果:image-20211026231553858

测试反序列化

    public static void main(String[] args)
            throws FileNotFoundException, ClassNotFoundException, IOException {
        System.out.println("--------------反序列化开始----------------");
        Data.deserialize();
        System.out.println("--------------序列化结束----------------");
    }

运行结果:image-20211026231509582

注意点:

  1. transient变量不参与序列化。从上面我们可以看到,transient变量序列化前是2,反序列化后却为null。
  2. 静态变量是类变量,不是对象变量。所以不参与序列化。从上面我们可以看到, 静态变量序列化前是1024,反序列化后却为初始值1。
  3. 序列化ID:序列化id相当于是序列化对象的唯一标识。序列化对象时,序列化ID也会被保存在文件中。反序列化时,会检查二进制文件中的序列化ID和这个类中的序列化ID是否一致,一致才能反序列化为对象,不一致则抛出InvalidClassException异常。当类没有定义序列化ID,Java会自动帮我们生成一个。但当我们改变(如新增类的属性)这个类时,则个序列化ID也会改变,导致序列化ID不一致。这时反序列化就会抛出InvalidClassException异常。所以一般我们都会自己定义一个序列化ID,这时我们改变(如新增类的属性)这个类时,序列化ID也会不会改变。就可以反序列化成功。

举例:继续拿上个例子举例,上面我们没有自己定义一个序列化ID

先序列化

 public static void main(String[] args)
            throws FileNotFoundException, ClassNotFoundException, IOException {
        Data data = new Data("2",123, "data-serialization");
        Data.one="1024";
        System.out.println("--------------序列化开始----------------");
        data.serialize();
        System.out.println("--------------序列化结束----------------");
    }

然后我们在类中新增一个属性

public class Data implements Serializable {
  ………………其他相同…………………………
   //新增属性
    private String ms;
  …………………其他相同………………………
}

然后反序列化

    public static void main(String[] args)
            throws FileNotFoundException, ClassNotFoundException, IOException {
        System.out.println("--------------反序列化开始----------------");
        Data.deserialize();
        System.out.println("--------------序列化结束----------------");
    }

运行结果:我们可以看到流中的序列化id和本地序列化id不一致,才导致InvalidClassException异常。image-20211026234711985

现在我们加上序列化id

public class Data implements Serializable {
  ………………其他相同…………………………
     private static final long serialVersionUID = 3604972003323896788L;
  …………………其他相同………………………
}

然后序列化

 public static void main(String[] args)
            throws FileNotFoundException, ClassNotFoundException, IOException {
        Data data = new Data("2",123, "data-serialization");
        Data.one="1024";
        System.out.println("--------------序列化开始----------------");
        data.serialize();
        System.out.println("--------------序列化结束----------------");
    }

再新增属性

public class Data implements Serializable {
  ………………其他相同…………………………
     private static final long serialVersionUID = 3604972003323896788L;
   //新增属性
    private String ms;
  …………………其他相同………………………
}

再反序列化

    public static void main(String[] args)
            throws FileNotFoundException, ClassNotFoundException, IOException {
        System.out.println("--------------反序列化开始----------------");
        Data.deserialize();
        System.out.println("--------------序列化结束----------------");
    }

运行结果:可以看到尽管我新增了一个属性ms,仍能反序列化成功。

image-20211027000330374
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值