序列化--用计算机才有的语言记录数据

本文详细介绍了Java中的序列化和反序列化概念,包括如何使对象可序列化、序列化和反序列化操作,以及处理serialVersionUID不一致导致的反序列化失败问题。通过示例代码展示了如何在类中定义serialVersionUID,以及如何使用try-catch处理异常,确保序列化和反序列化的稳健性。此外,还提供了序列化和反序列化的封装方法,简化了代码实现。
摘要由CSDN通过智能技术生成

序列化和反序列化

1、定义:

	百度百科上的定义:是将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。以后,可以通过从存储区中读取或反序列化对象的状态,重新创建该对象。

序列化百度百科

2、初步理解

	序列化和反序列化:就是将一个可序列化的Object对象用一种系统才看的懂的方式在指定文件中写入和读出。计算机使用的这种方式我们看不懂,我们也没有必要看懂,我们只需要知道它写入和读出的内容而已。就好像是我们在翻译官的陪同下和一个外国人聊天,我们不需要知道那个外国人说了什么,我们只需要知道翻译官翻译出来的话就可以了。

(1)要使对象变得可序列化,只需要实现Serializable接口即可,在实现Serializable后,无需实现任何的抽象方法。


import java.io.Serializable;

public class Admin implements Serializable {
    private String ID;
    private String password;

    public Admin() {
    }

    public Admin(String ID, String password) {
        this.ID = ID;
        this.password = password;
    }

    @Override
    public String toString() {
        return "Admin{" +
                "ID='" + ID + '\'' +
                ", password='" + password + '\'' +
                '}';
    }

    public String getID() {
        return ID;
    }

    public void setID(String ID) {
        this.ID = ID;
    }


    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
}

(2)序列化和可序列化:

import java.io.*;

public class Test {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        Admin admin1 = new Admin("123","123");
        //序列化
        /*
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("admin.txt"));
            拆分出来就是下面的两行
        */
        FileOutputStream fos = new FileOutputStream("admin.txt");//创建文件输出流
        ObjectOutputStream oos = new ObjectOutputStream(fos);//创建一个Object的输出流
        oos.writeObject(admin1);//将admin1写入admin。txt中
        oos.close();

        //反序列化
        /*
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("admin.txt"));
            拆分出来就是下面的两行
        */
        FileInputStream fis = new FileInputStream("admin.txt");//创建文件输入流
        ObjectInputStream ois = new ObjectInputStream(fis);//创建一个Object的输入流
        Admin admin2 = (Admin) ois.readObject();//将admin.txt中的内容反序列出来,并强转成Admin类型
        System.out.println(admin2.toString());
    }
}

序列化结果:我们可以看到admin1对象写入文件后的结果是一堆的乱码,我们根本就看不懂
序列化结果
反序列化结果:但是反序列化之后,我们可以看到反序列化所读出的数据和序列化前写入的数据是一样的。
反序列化

3、serialVersionUID

	在之前的序列化和反序列化中,其实需要满足一个条件,那就是Admin类没有过改动,一旦Admin类有所改动,反序列化就会失败,也就是无法读出数据。
	如果,在序列化后修改了Admin类的内容(如增加name属性),然后再反序列化,则会报一下错误:

UID错误
从上面的报错我们可以看到,此次报错是由于serialVersionUID不一致二导致的,
那么serialVersionUID是啥,为啥它就忽然蹦出来了,为啥它就忽然之间就不一致了呢?
(1)原因:
serialVersionUID是计算机在进行序列化时用于标识写入和读取的内容的,和相当于是可序列化类的“身份证”,计算机在序列化(写入数据)时,如果我们没有给这个数据的类一个“身份证”(也就是serialVersionUID),那么计算机就会自动生成一个“身份证”;在反序列化(读出数据)时,计算机会根据数据的类的“身份证”来读取这个数据,如果这个“身份证”不一致,那么反序列化就会失败。而对类的修改恰好就会改变这个自动生成的“身份证”的数值。
(2)解决办法:
其实解决办法很简单,既然计算机自动生成的“身份证”可以会改变,那我们就自己定义一个“身份证”,并且让这个“身份证”这辈子都不能改变并且和这个类绑定在一起就可以,这个“身份证”就是serialVersionUID,而要使其一直不变,只需要将其定义成静态常量就可以了。所以只要在为类实现可序列化接口时,多定义一句话就可以了。

		private static final long serialVersionUID = 1L;

(3)测试:
在定义Admin类时,我们只多定义一个静态常量serialVersionUID,这时其运行结果为:
在这里插入图片描述
在为Admin类添加属性name后,其反序列化不报错,name显示为空是因为我们存储时就没有为name赋值。
在这里插入图片描述

4、改进

我们可以不将异常抛出,而是直接使用try-catch来直接处理异常,由于我们的各种流都是在写入或读出之后就要关闭,所以我们可以将其和try-with-resources搭配使用。
(1)将序列化的代码修改并包装在一个方法内:

	 /**
     * 序列化
     * @param admin
     */
    public static void serialize(Admin admin){
        try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("admin.txt"))){

            oos.writeObject(admin);
            oos.flush();

        } catch (FileNotFoundException e) {
            System.out.println("找不到文件异常的处理");
        } catch (IOException e) {
            System.out.println("IO异常的处理");
        }
    }

(1)将反序列化的代码修改并包装在一个方法内:

    /**
     * 反序列化
     * @return
     */
    public static Admin deserialize(){
        Admin admin = new Admin();
        try( ObjectInputStream ois = new ObjectInputStream(new FileInputStream("admin.txt"))) {

            admin = (Admin) ois.readObject();

        } catch (FileNotFoundException e) {
            System.out.println("找不到文件异常的处理");
        } catch (IOException e) {
            System.out.println("IO异常的处理");
        } catch (ClassNotFoundException e) {
            System.out.println("找不到类的异常的处理");
        }
        return admin;
    }

(3)调用序列化和反序列化的main方法

 public static void main(String[] args) {
        Admin admin1 = new Admin("123","123","黄一");
        //序列化
        serialize(admin1);
        //反序列化
        Admin admin2 = deserialize();

        System.out.println("写入的数据"+admin1.toString());
        System.out.println("读出的数据"+admin2.toString());
    }

(4)测试结果:
在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值