为什么要实现Serializable

提几个问题

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、查看结果发现报错了
在这里插入图片描述

解决问题

这个问题是因为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

我们看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、执行代码,我们发现报错了
在这里插入图片描述
意思就是两个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属性,就会出现警告。
在这里插入图片描述

参考资料

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值