Java-序列化和反序列化简单解释以及代码实现示例


序列化流

1.简介

将短期存储的数据实现长期存储,这个过程对应的流就是序列化流

数据的存储分成两类

  1. 短期存储:存放在内存中,随着程序的关闭而释放。如:对象、集合、变量、数组等
  2. 长期存储:存储在磁盘中,即使程序关闭了,数据依然存在。如:文件

序列化:将数据从内存放入磁盘中,可以实现数据的长久保存。

反序列化:将数据从磁盘放入内存中。

2.注意事项

ObjectInputStreamObjectOutputStream,主要是用来做对象的序列化和反序列化的。

序列化、反序列化,是对象的持久化存储的一种常用手段。

所有的序列化到本地的类的对象,类必须实现java.io.Serilizable接口。

实现Serilizable接口的类可以达到的目的:

  1. 可以进行序列化
  2. 进行序列化的类的元素必须都支持序列化
  3. 可序列化类的所有子类型本身都是可序列化的
  4. 接口本身没有方法或字段,只是用来表示可序列化的语义

如果需要序列化多个文件到本地,尽量不要序列化到一个文件中。如果需要序列化多个文件到本地,通常采用的方法是存集合将多个对象存入一个集合中,然后将这个集合序列化到本地中。

3.常见问题

  1. ClassNotFoundException:当前的类没有找到
    原因:反序列化在执行的时候依赖字节码文件,当类没有类,字节码文件无法创建,反序列化失败
  2. java.io.InvalidClassException:无效的类
    原因:没有声明自己的serialVersionUID,而使用的系统的,在进行反序列化的时候类被改动了,系统认为现在的类已经不是原来的类了,认为此类无效
  3. 使用系统的serialVersionUID和自定义UID的区别?
    使用系统的的UID的时候:id不能手动设置,使用的是编译器默认生成的。一旦类发生了改动,id会重新赋值;
    使用自定义的UID的时候:序列化和反序列化的时候,id不会发生变化。所以当反序列的时候,即使对类进行了一些改动,也能继续反序列化。

示例代码

    package com.cq.test;
    
    import java.io.*;
    import java.util.ArrayList;
    import java.util.List;
    
    /**
     * @author: Mercury
     * Date: 2022/4/6
     * Time: 9:02
     * Description:序列化流
     * Version:1.0
     */
    public class SerializableTest {
    
    
        public static void main(String[] args) {
    
    
            test1();
            test2();
        }
        //序列化
        public static void test1(){
    
    
            try (ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("F:\\bigDataWorkSpace\\part01\\day21_0406\\person.txt"));){
    
    
                //对对象进行序列化
                List<Person> list = new ArrayList<>();
                list.add(new Person("张三",20,177));
                list.add(new Person("wangwu",21,177));
                //可序列化类的所有子类本身都是可序列化的
                list.add(new Child("lisi",20,155,100));
                //将多个对象序列化的时候,需要先放入一个集合中,然后再序列化
                objectOutputStream.writeObject(list);
            } catch (IOException e) {
    
    
                e.printStackTrace();
            }
        }
        //逆序列化
        public static void test2(){
    
    
            try(ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("F:\\bigDataWorkSpace\\part01\\day21_0406\\person.txt"));) {
    
    
                //反序列化
                //反序列多个对象的时候,同样需要一个集合来保存反序列化的多个对象
                List list = (ArrayList)objectInputStream.readObject();//需要强制转换ArrayList
                System.out.println(list);
            } catch (IOException e) {
    
    
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
    
    
                e.printStackTrace();
            }
        }
    }
    //Person类的对象可以实现序列化,必须让其实现Serializable接口
    class Person implements Serializable{
    
    
        // UID由用户进行指定,默认值为1L
        public static final long serialVersionUID = -24323423423423221L;
        private String name;
        private int age;
        private double height;
    
        public void show(){
    
    
            System.out.println("show--Person");
        }
    
        @Override
        public String toString() {
    
    
            return "Person{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    ", height=" + height +
                    '}';
        }
    
        public Person() {
    
    
        }
    
        public Person(String name, int age, double height) {
    
    
            this.name = name;
            this.age = age;
            this.height = height;
        }
    
        public String getName() {
    
    
            return name;
        }
    
        public void setName(String name) {
    
    
            this.name = name;
        }
    
        public int getAge() {
    
    
            return age;
        }
    
        public void setAge(int age) {
    
    
            this.age = age;
        }
    
        public double getHeight() {
    
    
            return height;
        }
    
        public void setHeight(double height) {
    
    
            this.height = height;
        }
    }
    
    //可序列化类的所有子类本身都是可序列化
    class Child extends Person{
    
    
        private double weight;
    
        public Child() {
    
    
        }
    
        public Child(double weight) {
    
    
            this.weight = weight;
        }
    
        public Child(String name, int age, double height, double weight) {
    
    
            super(name, age, height);
            this.weight = weight;
        }
    
        public double getWeight() {
    
    
            return weight;
        }
    
        public void setWeight(double weight) {
    
    
            this.weight = weight;
        }
    
        @Override
        public String toString() {
    
    
            return "Child{" +
                    "weight=" + weight +
                    '}';
        }
    }

注意

  • 要想对象可以实现序列化,那么必须让该类实现Serializable接口
  • 未实现Serializable接口的类无法使其任何状态序列化或反序列化
  • 不仅要求当前类可序列化,而且要求当前类的所有元素本身都是可序列化的
  • 将多个对象序列化的时候,需要将其先放入一个集合中,然后再进行序列化;反序列化的时候同样,但需要类型强制转换

总结

  • 合理使用序列化流和反序列化流,要与输入流和输出流配合使用
  • 进行序列化的类一定要实现Serializable接口,只要实现了接口就可以序列化,包括集合、包装类等
  • 进行序列化的类要保证当前类与内部的类都要实现Serializable接口

猜你喜欢

转载自blog.csdn.net/qq_45263520/article/details/123984008