序列化和反序列化

序列化和反序列化

序列化(Serialize):java对象存储到文件中。将java对象的状态保存下来的过程。

反序列化(DeSerialize):将硬盘上的数据重新恢复到内存当中,恢复成java对象。

。。。。

  1. java.io.NotSerializableException 异常

    Student对象不支持序列化

  2. 参与序列化和反序列化的对象,必须实现Serializable接口

    public class Student implements Serializable {
        //java虚拟机看到这个接口之后,会为该类自动生成一个版本化序列号。
        //这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。
        private int    no;
        private String name;
    
        public Student() {
        }
    
        public Student(int no, String name) {
            this.no = no;
            this.name = name;
        }
    
        public int getNo() {
            return no;
        }
    
        public void setNo(int no) {
            this.no = no;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    '}';
        }
    }
    
  3. 通过源代码发现,Serializable接口只是一个标志接口:

    public interface Serializable { }

    这个接口当中什么代码都没有。只起到标识的作用,java虚拟机看到这个类实现了这个接口,可能会对这个类进行特殊待遇。

    Seralizable这个标志接口是给java虚拟机参考的,java虚拟机看到这个接口之后,会为该类自动生成一个序列化版本号。

    这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。

    public class ObjectOutputStreamTest01 {
        public static void main(String[] args) {
            Student zhangsan = new Student(5, "zhangsan");
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(new FileOutputStream("student"));
                oos.writeObject(zhangsan);
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if ( oos != null) {
                    try {
                        oos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
    
        }
    }
    
    
    public class ObjectInputStreamTest01 {
        public static void main(String[] args) {
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(new FileInputStream("student"));
                //反序列化回来是一个学生对象,所以会调用学生的toString()方法
                System.out.println(ois.readObject());
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if (ois != null) {
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
    
  4. 序列化版本号有什么用

    如果某一个项目再十年前序列化了一个学生类,过了很久,Student这个类源代码改动了。

    源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。

    并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。

    java.io.InvalidClassException:

    ​ com.bean.Student;

    ​ local class incompatible:

    ​ stream classdesc serialVersionUID = 5121880095660446367(十年前),

    ​ local class serialVersionUID = -5381600005822386241(十年后)

    java语言中是通过什么机制来区分类的

    1. 首先通过类名进行比对,如果类名不一样,肯定不是同一个类
    2. 如果类名一样,靠序列化版本号进行区分。

    小鹏编写了一个类:com.bean.Student implements Serializable

    小李编写了一个类:com.bean.Student implements Serializable

    不同的人编写了同一个类,但这两个类确实不是同一个类这个时候序列化版本号就有用了

    优点:对于java虚拟机来说,java虚拟机是可以区分开这两个类的,因为这两个类都是先了Serializable接口,都有默认的序列化版本号,他们的序列化版本号不一样。所以区分开了。(这是自动生成序列化版本号的好处)

    缺陷:一旦代码确定之后,不能进行后续的代码修改,因为只要修改,必然会重新编译,此时会生成全新的序列化版本号,此时java虚拟机会认为这是一个全新的类。

    结论:凡是一个类实现了Serializable接口,建议给该类提供一个固定不变的序列化版本号。以后这个类即使代码修改了,但是版本号不变,java虚拟机会认为是同一个类

    建议将序列化版本号手动的写出来,不建议自动生成

    public class Student implements Serializable{
        //java虚拟机看到这个接口之后,会为该类自动生成一个版本化序列号。
        //这里没有手动写出来,java虚拟机会默认提供这个序列化版本号。
        //建议将序列化版本号手动写出来。不建议自动生成
        private static final long serialVersionUID = 111L;
        private int    no;
        private String name;
    
        //过了很久,Student这个类源代码改动了。
        //
        //源代码改动之后,需要重新编译,编译之后生成了全新的字节码文件。
        //
        //并且class文件再次运行的时候,java虚拟机生成的序列化版本号也会发生相应的改变。
        private int age;
        private String email;
    
        public Student() {
        }
    
        public Student(int no, String name) {
            this.no = no;
            this.name = name;
        }
    
        public int getNo() {
            return no;
        }
    
        public void setNo(int no) {
            this.no = no;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Student{" +
                    "no=" + no +
                    ", name='" + name + '\'' +
                    '}';
        }
    
    }
    
  5. IDEA工具自动生成序列化版本号

    Settings --> Editor --> Inspections --> 搜索Serializable

    。。。

    最后在类名那里使用快捷键alt + Enter就可以自动生成序列化版本号

  6. 序列化与反序列化多个对象

    存储第二个对象就会报错,所以使用集合存储多个对象

    //序列化
    public class ObjectOutputStreamTest02 {
        public static void main(String[] args) {
            List<User> userList = new ArrayList<>();
    
            userList.add(new User(1,"zhangsan"));
            userList.add(new User(2,"lisi"));
            userList.add(new User(3,"wangwu"));
            userList.add(new User(4,"zhaoliu"));
            ObjectOutputStream oos = null;
            try {
                oos = new ObjectOutputStream(new FileOutputStream("users"));
    
                //序列化一个集合,这个集合对象中放了很多其他对象。
                oos.writeObject(userList);
                oos.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }finally {
                if (oos != null) {
                    try {
                        oos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                }
            }
        }
    }
    
    
    //反序列化
    public class ObjectInputStreamTest02 {
        public static void main(String[] args) {
            ObjectInputStream ois = null;
            try {
                ois = new ObjectInputStream(new FileInputStream("users"));
    
                List<User> userList = (List<User>)ois.readObject();
                for (User user : userList) {
                    System.out.println(user);
                }
            } catch (IOException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } finally {
                if (ois != null) {
                    try {
                        ois.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
    
                }
            }
        }
    }
    /*
    User{no=1, name='zhangsan'}
    User{no=2, name='lisi'}
    User{no=3, name='wangwu'}
    User{no=4, name='zhaoliu'}*/
    
    
  7. 不希望某个元素序列化

    	private int no;
        private transient String name;
    
    //序列化与反序列化后的结果为
    /*
    User{no=1, name='null'}
    User{no=2, name='null'}
    User{no=3, name='null'}
    User{no=4, name='null'} 
    */
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值