JAVA学习-序列化

一、序列化与反序列化

        Java序列化是指将数据结构或Java对象转换成二进制串的过程,而Java反序列化是指将在序列化过程中所生成的二进制串恢复成数据结构或者Java对象的过程。

序列化

        在Java中,对象的序列化是通过实现Serializable接口来实现的。Serializable接口是一个空接口,没有任何方法,它仅仅是一个标记接口,用于指示该类的对象可以被序列化。当一个类实现了Serializable接口后,它的对象就可以被序列化成字节流,然后可以通过网络传输或存储在本地文件中。

对象序列化的过程是将对象转换成字节序列的过程,主要包括以下几个步骤:

  1. 创建一个输出流,用于将字节写入到目标位置,可以是文件、数据库或网络连接等。
  2. 将对象通过输出流进行序列化,将对象转换成字节序列,并写入到输出流中。
  3. 在接收端,通过输入流读取字节序列,并将字节序列转换成对象。

对象序列化的最主要的用处是在传递和保存对象的时候保证对象的完整性和可传递性,可以应用到:

  1. 分布式系统:在分布式计算中,可以将Java对象序列化为字节流后,在网络中传输到其他节点,然后在接收端将字节流反序列化为对象使用,从而实现分布式计算。
  2. 缓存:序列化对象后,可以将其存储在缓存系统中,以避免频繁数据库查询。
  3. 数据持久化:将对象以序列化的形式存储到文件、数据库或其他数据存储中,以实现数据的持久化
  4. 网络通信:在网络通信中,可以将Java对象序列化为字节流进行传输,然后在接收端将字节流反序列化为对象来进行处理。

总的来说,对象的序列化是将对象转换成字节序列的过程,可以用于对象的存储、传输和共享等操作,使得对象的状态可以得到保存和重建。

反序列化 

        在使用序列化后的数据时,会从文件或网络中获取到序列化后的对象字节流,并根据该字节流重新构建出原始的Java对象。通过反序列化,我们可以将对象从持久性存储中恢复出来使用。

二、常见应用

        我们常见的SpringBoot开发的项目中,很少需要实现序列化接口,因为spring框架会将我们的对象转换为json字符串。数据通常是通过HTTP协议进行传输的,也是使用JSON将数据转换为可传输格式。那为什么JSON可以转换为可传输格式呢?

因为String字符串底层也实现了序列化,后端的数据想要响应给浏览器,就必须进行网络传输,也就意味着需要序列化操作。通过将数据转换为JSON字符串,可以将复杂的数据结构进行序列化,然后通过HTTP协议进行传输。在接收端,可以将JSON字符串反序列化为对应的数据结构,进而进行数据的处理和展示。

三、类的序列化和反序列化

        当这个类需要保存到数据库或者文件里时,就可以通过实现序列化接口java.io.Serializable来进行序列化和反序列化操作。

下面实际操作下:

1、实现类的序列化和反序列化

这是一个宠物类

gender属性使用transient关键字修饰,表示不能被序列化

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Pet implements Serializable{

    @ExcelProperty(value = "宠物姓名")
    private String name;
    @ExcelProperty(value = "种类")
    private Integer type;
    @ExcelProperty(value = "年龄/月")
    private Integer age;
    @ExcelProperty(value = "性别")
    private transient Byte gender;
    @ExcelProperty(value = "领养人")
    private String owner;
    
}

将对象序列化为字节数组

public static byte[] serializationPet() throws  Exception{
        Pet pet = new Pet("招财",PetTypeEnum.CAT.getType(),1, (byte) 1,null);
        System.out.println("宠物:"+ pet);
        //创建ByteArrayOutputStream(或其他类型的OutputStream,
        // 如文件输出流FileOutputStream)来接收序列化后的对象数据
        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        //通过ObjectOutputStream将对象序列化,并将序列化后的对象写入到OutputStream中
        objectOutputStream.writeObject(pet);
        objectOutputStream.close();
        //获取序列化后的字节数组
        byte[] serializedObject = byteArrayOutputStream.toByteArray();
        System.out.println("序列化为字节数组:");
        System.out.println(Arrays.toString(serializedObject));
        return serializedObject;
    }

将字节数组反序列化对象

public static void deSerializationPet(byte[] outputStream) throws Exception{
        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(outputStream);
        ObjectInputStream inputStream = new ObjectInputStream(byteArrayInputStream);
        // 从 ObjectInputStream 中读取对象并进行类型转换
        Pet pet = (Pet) inputStream.readObject();
        inputStream.close();
        System.out.println("反序列化后:"+pet.toString());
    }

打印结果

可以看到序列化前gender=1,反序列化后gender是null,说明序列化的时候没有将被transient关键字修饰的变量进行持久化。

2、将对象序列化到文件里

创建ObjectOutputStream对象依赖FileOutputStream文件输出流,通过writeObject()方法将对象序列化到文件里

public static void writePetToTxt() throws Exception{
        Pet pet = new Pet("咪咪",PetTypeEnum.CAT.getType(),10,(byte) 0,"shijinge");
        File file = new File("pet.txt");
        //创建输出流对象,依赖的是文件输出流FileOutputStream
        ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(file));
        //通过writeObject()方法将对象序列化为文件
        outputStream.writeObject(pet);
        outputStream.close();
    }

ObjectOutputStream.writeObject()的作用是把一个实例的对象以文件的形式保存到磁盘上,
这个过程就叫Java对象的持久化。

创建ObjectInputStream对象依赖FileInputStream文件输入流,通过readObject()方法将文件反序列化成指定类型对象

public static void readPetFromTxt() throws Exception{
        File file = new File("pet.txt");
        //文件输入流
        ObjectInputStream inputStream = new ObjectInputStream(new FileInputStream(file));
        //通过readObject()方法将文件反序列化为指定类型
        Pet pet = (Pet) inputStream.readObject();
        inputStream.close();
        System.out.println("从文件反序列化后对象:"+pet.toString());
    }

序列化多个对象到文件

writeObject()方法不能追加,写入多个对象会覆盖,如果要写入多个对象可以这样写:

 outputStream.writeObject(pets);

相应反序列化的时候这样写

        List<Pet> pets = (List<Pet>) inputStream.readObject();

如果Pet类没有实现Serializable接口时,进行序列化和反序列化会报异常问题:如果序列化对象到文件里后,Pet类增加或删掉了一个属性,更改了Pet的状态,这个时候反序列化能成功吗?

这就是serialVersionUID号的作用了,它是序列化前后的唯一标识符,如果没有显示声明的话,编译器会字段声明一个。如果对象的结构信息发生变化,这个id也会变。序列化后的字节流会带有序列号id,反序列化时会用类当前的id去对比,一致的话才能反序列化。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值