Java序列化和反序化

一、什么是序列化和反序列化

Java序列化就是指把Java对象转换为字节序列的过程
Java反序列化就是指把字节序列恢复为Java对象的过程。

二、为什么要把一个对象序列化

正常情况下,Java new出的对象,是保存在内存当中的,是不能持久化保存的,也不能直接在网络中传输,如何解决呢?就是把Java对象转换为byte字节数据,以字节的方式去实现持久化保存和网络传输。而反序列化,就是把须列化后的数据,重新恢复成内存中的Java对象。
总之,序列化,就是对一个Java对象的保存和重建的过程。

三、Java实现序列化的过程

为了让一个Java对象能序列化,我们需要为这个Java对象实现Serializable接口,像下面这样,这个方法和普通的Bean来说,多继承了这个接口,这个接口没有实现实现任何方法,它是为什么告诉编译器,这个接口可以序列化。


@Data
public class User implements Serializable {
    
    


    private String name;

    private int age;

    private String  sex;

    private String phone;


}

这个类可以序列化了,但如何序列化让它能本地存储呢?执行下面的write方法,将会在D盘根目录下创建User类的序列化文件,执行read方法可以把序列化文件转变成对象。

public class Client {
    
    

    @Test
    public void write() throws Exception{
    
    
        User user = new User();
        user.setAge(15);
        user.setName("张三");
        user.setPhone("123");
        FileOutputStream fileOutputStream = new FileOutputStream("D://out.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(user);

    }

    @Test
    public void read() throws Exception{
    
    
        FileInputStream fileInputStream = new FileInputStream("D://out.txt");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        User o = (User)objectInputStream.readObject();
        System.out.println(o.toString());
    }

}

read方法运行结果,序列化出来的对象,拥有序列化之前对象的值。

在这里插入图片描述

四、不能被序列化的对象

Java对象中,如果一个字段被transient修饰,或者这个字段是static静态字段,这个类将不会被序列化,意味着,这个对象被序列化后,再次反序列化成Java对象后,对于的字段值为null。
在这里插入图片描述

五、序列号的作用

我们的类是不断的变动的,我们把一个对象序列化到本地文件后,有一天,这个对象的类发送了改变,我们用这个改变后的类接收序号化文件,会发生什么?把name和age注释掉,然后去反序列化。

public class User implements Serializable {
    
    


//     private String name;
//
//    transient private int age;

    private String  sex;

    private String phone;

    
}

public class Client {
    
    

    @Test
    public void write() throws Exception{
    
    
        User user = new User();
//        user.setAge(15);
//        user.setName("张三");
        user.setPhone("123");
        FileOutputStream fileOutputStream = new FileOutputStream("D://out.txt");
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream);
        objectOutputStream.writeObject(user);

    }

    @Test
    public void read() throws Exception{
    
    
        FileInputStream fileInputStream = new FileInputStream("D://out.txt");
        ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
        User o = (User)objectInputStream.readObject();
        System.out.println(o.toString());
    }

}




结果就是

java.io.InvalidClassException: com.example.service.demo01.User; local class incompatible: stream classdesc serialVersionUID = -118799779803260725, local class serialVersionUID = 1681826866445576943

这个报错是什么意思?是这个类和序列化文件里的类的序列号不一样,无法反序列化。
这里出现了一个问题,什么是序列号?

序列号是一个长整型的数据,一个类的序列号,是根据这个类的成员变量计算出来,如果成员变量发生改变,序列号也会发生改变,只有序列化文件的序列号和类的序列号相同,才能反序列化成功。
所以这个报错就很容易理解了,在改动前,类有三个变量,序列号的值假设是3,序列化的文件也是3,删除一个变量后,只剩两个变量,假设序列号是2,这样和序列化文件的序列号就不一样了,所以无法反序列化。

有时候,我们希望,即使类发生了改变,也能反序列化成功,比如之前有现在只剩3个字段,序列化的文件有4个字段,我们只序列化现在的类有的字段,那该怎么做?
我们可以手动为一个类设置序列号,像这样:
在这里插入图片描述
这样,即使类发生了改变,但是序列号我们已经手动写死了,之后类再怎么发生变化,反序列化也不会报错,只会序列话那些还能对应上的值。

猜你喜欢

转载自blog.csdn.net/qq_45171957/article/details/123858691