likes
comments
collection
share

JAVA的序列化和反序列化

作者站长头像
站长
· 阅读数 4

1.谈到了序列化,那么我们必须要知道Java里面的序列化接口Serializable,相信大家打开这个类想查看源码时没结果发现这个接口竟然是空的。 JAVA的序列化和反序列化 想必这时候大家肯定是一脸懵逼, JAVA的序列化和反序列化 一个空接口能实现什么功能呢,其实啊,这个Serializable接口的作用只有标识作用,即只是个标识接口。我们可以举个例子:

比如在课堂上有位学生遇到一个问题,于是举手向老师请教,这时老师帮他解答,那么这位学生的举手其实就是一个标识,自己解决不了问题请教老师帮忙解决。在Java中的这个Serializable接口其实是给jvm看的,通知jvm,我不对这个类做序列化了,你(jvm)帮我序列化就好了。

因此大家应该也明白了,Serializable接口就是Java提供用来进行高效率的异地共享实例对象的机制,实现这个接口即可,当然了,通过这个接口的注释也可以看出,它强烈建议我们自己定义一个serialversionUID,因为默认生成的serialversionUID对class极其敏感,在反序列化的时候很容易抛出InvalidClassException异常。

2.既然已经了解了这个序列化接口Serializable,那么就可以写序列化和反序列化了,所谓序列化就是指将对象转换为字节序列的过程,说白了,就是将序列化的对象存储成文件,直接看代码吧:

(1).首先就是转化的对象User类,代码如下:

package com.example.main;

import java.io.Serializable;

//序列化的对象必须实现Serializable接口。
public class User implements Serializable{
    private String name;
    private String passWord;

    public User(String name, String passWord) {
        this.name = name;
        this.passWord = passWord;
    }

    public String getName() {
        return name;
    }

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

    public String getPassWord() {
        return passWord;
    }

    public void setPassWord(String passWord) {
        this.passWord = passWord;
    }
    //此处之所以写toString()方法就是为了方便反序列化后能够在终端看到我们能看懂的字符串,而不是类名和哈希码。
    //因为每个Java类都默认继承了Object类,而且此处就算不写重写注解也无妨,但是为了便于阅读,还是建议写上好。
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + ''' +
                ", passWord='" + passWord + ''' +
                '}';
    }
}

(2).以下代码就是主方法执行序列化操作。

package com.example.main;

import java.io.*;

public class Main {
    public static void main(String[] args) {
        //里面的./就是进入根目录。
        File file = new File("./name.txt");
        try {
            //如果文件路径不存在,那么就会创建一个。
            if (file.createNewFile()){
                System.out.println("创建成功");
            } else {
                System.out.println("文件已经创建");
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        //以下就是序列化过程,好好思考一下。
        User user = new User("jinxuan",21);
        try {
            //注意由于这里是要将对象写入文件,故应该使用objectOutputStream类。
            ObjectOutputStream stream = new ObjectOutputStream(new FileOutputStream(file));
            stream.writeObject(user);
            stream.close();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

但是我们通过查看name.txt文件就会发现里面都是乱码,这是因为我们在写入二进制数据而不是文件。

3.既然序列化完了,肯定就该反序列化了,反序列化就是序列化的反过程,将字节序列转换为JAVA对象,直接看代码如下:

代码如下:

package com.example.main;

import java.io.*;

public class Main {
    public static void main(String[] args) {
        try {
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("./name.txt"));
            try {
                Object o = objectInputStream.readObject();
                User user = (User) o;
                System.out.println(user);
            } catch (ClassNotFoundException e) {
                throw new RuntimeException(e);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

    }

}

关于我们上面说到的SerialVersionUID,这个可以的话必须要自己定义一个,而且尽量用Private修饰,因为这个也没必要让外部类修改,之所以加上这个ID的目的就是为了在反序列化的时候操作系统会进行检测这个ID和序列化的时候的ID是否相同再进行反序列化,而JVM之所以会默认生成这样一个SerialVersionUID就是为了使其可以进行持久化,即有了标记才可以使得JVM允许其IO系统将其转换为字节数据。