为什么要实现Serializable

目录

  • 提几个问题
  • 序列化和反序列化
  • Java如何实现序列化和反序列化
    • 我们来写一个小demo:
    • 解决问题
    • 为什么必须要实现Serializable
  • 什么是serialVersionUID
    • serialVersionUID是什么
  • IDEA设置serialVersionUID技巧
  • 参考资料

提几个问题

1、序列化是什么?
2、Java序列化为什么要实现Serializable?
3、为什么要明确定一个serialVersionUID,后期还不允许修改呢?

序列化和反序列化

我们都知道在计算机世界是只认识二进制格式的数据的,所以如果我们想传输文件,保存文件,都需要将我们看到的转成二进制流(即byte[]数组)才能进行网络传输或者保存到磁盘。

将一个对象转成二进制流,这就是序列化。转为二进制流的对象就可以在网络之间进行传输,或者保存到磁盘。将这个二进制流再转为一个对象,就是反序列化。

Java如何实现序列化和反序列化

本质就是将对象转为二进制流,然后再将二进制流转为对象

我们来写一个小demo:

1、创建一个对象,序列化和反序列化这个对象

public class Person{
    private String name;
    private int age;

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

    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

2、序列化和反序列化

public class SerializationDemo {
    public static void main(String[] args) {
        // 创建Person对象
        Person person = new Person("John Doe", 30);

        // 序列化对象到文件
        try {
            FileOutputStream fileOut = new FileOutputStream("person.ser");
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();
            System.out.println("Person对象已序列化到person.ser文件");
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 从文件反序列化对象
        try {
            FileInputStream fileIn = new FileInputStream("person.ser");
            ObjectInputStream in = new ObjectInputStream(fileIn);
            Person deserializedPerson = (Person) in.readObject();
            in.close();
            fileIn.close();
            System.out.println("从person.ser文件反序列化得到的Person对象:" + deserializedPerson);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

3、查看结果发现报错了
为什么要实现Serializable_第1张图片

解决问题

这个问题是因为Person类没有实现Serializable接口

1、我们来实现这个接口后再运行查看结果:

public class Person implements Serializable{
    private String name;
    private int age;

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

    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

2、查看结果
为什么要实现Serializable_第2张图片
我们看到运行结果都正确了

为什么必须要实现Serializable

我们看Serializable源码,发现它是一个空接口

public interface Serializable {
}

然后我们可以看源码的注释,注释说明只有类实现了此接口才能被标识为可以序列化。

由此我们发现这个接口就是起到一个标识的作用,在运行时被此接口标识的对象才能被序列化和反序列化,反之则不行。

什么是serialVersionUID

我们看阿里巴巴开发手册中此规范被标识为【强制】
在这里插入图片描述
1、那这个是个什么东西呢?
从字面意思就发现是序列化版本id,就是这个对象序列化时的版本号,在我们实现serialVersionUID的时候虽然我们没有明确指定是多少,但是Java底层帮我们默认生成了一个随机数。

2、serialVersionUID不一致会怎么样
不一致就不能进行反序列化,只有反序列化的对象和二进制流的serialVersionUID是一致的才能反序列化。
有可能我们在序列化时对象是正常的,在反序列化时的对象是序列化的对象不一致了,就会报错。因为他们的serialVersionUID不一致

3、写一个demo测试一下
我们知道Java会默认生成一个随机数,所以对象属性发生变化时,serialVersionUID也会变化

public class Person implements Serializable{

    private String name;
    private int age;

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

    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

1、先将Person序列化到本地文件

    /**
     * 序列化对象到文件
     *
     * @param person
     */
    public static void serialization(Person person, String fileName) {
        // 序列化对象到文件
        try {
            FileOutputStream fileOut = new FileOutputStream(fileName);
            ObjectOutputStream out = new ObjectOutputStream(fileOut);
            out.writeObject(person);
            out.close();
            fileOut.close();
            System.out.println("Person对象已序列化到person.ser文件");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

2、修改Person类,增加weight属性

public class Person implements Serializable{

    private String name;
    private int age;
    private int weight;

    public Person(String name, int age, int weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }

    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", weight=" + weight + "]";
    }
}

3、反序列化之前序列化的文件

    public static Person deserialization(String fileName) {
        Person deserializedPerson = null;
        // 从文件反序列化对象
        try {
            FileInputStream fileIn = new FileInputStream(fileName);
            ObjectInputStream in = new ObjectInputStream(fileIn);
            deserializedPerson = (Person) in.readObject();
            in.close();
            fileIn.close();
            System.out.println("从person.ser文件反序列化得到的Person对象:" + deserializedPerson);
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
        return deserializedPerson;
    }

4、执行代码,我们发现报错了
为什么要实现Serializable_第3张图片
意思就是两个serialVersionUID匹配不上不能反序列化

serialVersionUID是什么

到这里我们就能明白,serialVersionUID不一样是不能进行反序列化的,也能明白为什么要求我们要自己定义一个serialVersionUID且后期不能修改,这样我们后期Person类不论改了什么属性都可以正常进行序列化和反序列化。

1、我们来实现这个demo
给原Person类加上serialVersionUID,然后序列化到本地文件

public class Person implements Serializable{

    // 增加一个确定的serialVersionUID 
    private static final long serialVersionUID = 1L;

    private String name;
    private int age;

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

    public String toString() {
        return "Person [name=" + name + ", age=" + age + "]";
    }
}

2、修改Person属性,但是不要修改serialVersionUID值,然后对前面序列化的文件进行反序列化

public class Person implements Serializable{

    private static final long serialVersionUID = 1L;

    private String name;
    private int age;
    private int weight;

    public Person(String name, int age, int weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }

    public String toString() {
        return "Person [name=" + name + ", age=" + age + ", weight=" + weight + "]";
    }
}

3、查看结果
在这里插入图片描述
我们发现反序列化成功了。

IDEA设置serialVersionUID技巧

我们在IDEA中这样设置,在开发中如果实现了Serializable接口,但是没有写serialVersionUID属性,就会出现警告。
为什么要实现Serializable_第4张图片

参考资料

https://mp.weixin.qq.com/s/HP4P4IcD8oTEovBUSq54pA

你可能感兴趣的:(技术随笔,Java,序列化,反序列化,底层原理,代码实践)