zoukankan      html  css  js  c++  java
  • 对象序列化和反序列化

    在网络通信中,任何数据都是以二进制的形式来传输的。对象序列化可以把内存中的Java对象转成二进制流,而二进制流可以存放在本地磁盘文件中,通过网络或程序来获取该二进制流后,就能将该二进制流恢复成Java对象。序列化的这一过程就是将对象状态信息转换为可存储或传输的过程。

    对象序列化的作用:

    • 对象序列化可以把对象以字节序列的形式永久保存在磁盘中。
    • 对象序列化可以用于在网络中传输对象。
    • 对象序列化使得对象可以脱离程序的运行而独立存在。

    序列化与反序列化

    序列化是将一个Java对象写入IO流中,转换成字节序列,而反序列化是用IO流将字节序列恢复成Java对象。要实现对象序列化,该对象的类必须实现接口Serializable,该接口没任何方法,仅作标记,说明该类可以实现序列化。

    若序列化对象的成员变量是一个引用类型,则该引用类型变量的类也要实现Serializable接口,保证序列化过程中用到的类都要实现序列化,不然会出现异常。

    对象序列化步骤:

    1. 使用ObjectOuputStream,使用writeObject()将一个对象序列化。也就是将对象转成二进制流,存放在磁盘文件中,实现持久化。
    public class Person implements Serializable{
        private String name;
        private int age;
        private String sex;    
        public Person(String name, int age, String sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }/**省略setter 和 getter*/
    }
    
    //把对象写入序列化文件,完成对象序列化
    public class Test {
        public static void main(String[] args) throws Exception {
        FileOutputStream fos = new FileOutputStream("D:\Object01.txt");//存放对象字节序列的文件路径
        //对象输出流中的节点流是一个缓冲流,该流包装节点流,所以需要flush()
        ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 
        Person p = new Person("张三", 15, "");
        oos.writeObject(p);
        oos.flush();    
        }    
    } 

    对象反序列化步骤

    调用ObjectInputStream的readObject()方法读取序列化文件中的二进制流,转成对象

    FileInputStream fis = new FileInputStream("D:\Object01.txt");
            //创建一个ObjectInputStream输入流,节点流数据源是一个对象序列化文件
            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
            //读取Person对象
            Person p = (Person)ois.readObject();
            System.out.println(p.getName() + "||" + p.getAge() +"||" + p.getSex());

    使用反序列化的注意点

    • 反序列化将二进制流数据转成对象,所以在此之前要保证该类存在,不然Java对象没有存在意义。
    • 如果读取的序列化文件中存在多个对象,则必须按照他们序列化的顺序来读取,不然会出错。
    • 如果成员变量使用transient修饰,那么反序列化后,该成员变量数据没有。
    • 反序列化的对象没有使用构造器来初始化。
     

    测试序列化多个对象:

    public class Person implements Serializable{
        private String name;
        private int age;
        private transient String sex; //透明化,表示该成员变量不会序列化
        
        public Person(String name, int age, String sex) {
            this.name = name;
            this.age = age;
            this.sex = sex;
        }
        /** 省略getter 和 setter */
    }
    public class Test {
        public static void main(String[] args) throws Exception {
            //存放对象字节序列的文件路径
            FileOutputStream fos = new FileOutputStream("D:\MoreObject.txt");
            //对节点流使用了缓冲流,所以需要flush()
            ObjectOutputStream oos = new ObjectOutputStream(new BufferedOutputStream(fos)); 
            Person p = new Person("张三", 15, "");
            Person p1 = new Person("李四", 20, "");
            Person p2 = new Person("王五", 25, "");
            //序列化多个对象
            oos.writeObject(p);
            oos.writeObject(p1);
            oos.writeObject(p2);
            oos.flush();
            
            //创建一个对象输入流ObjectInputStream
            FileInputStream fis = new FileInputStream("D:\MoreObject.txt");
            ObjectInputStream ois = new ObjectInputStream(new BufferedInputStream(fis));
            //恢复多个对象
            Person per1 = (Person) ois.readObject();
            Person per2 = (Person) ois.readObject();
            Person per3 = (Person) ois.readObject();
    //        Person per4 = (Person) ois.readObject(); //EOFException
            
            System.out.println(per1.getName() + "||" + per1.getAge() +"||" + per1.getSex());
            System.out.println(per2.getName() + "||" + per2.getAge() +"||" + per2.getSex());
            System.out.println(per3.getName() + "||" + per3.getAge() +"||" + per3.getSex());
            
    //        输出结果:
    //        张三||15||null
    //        李四||20||null
    //        王五||25||null
        }
    }
    • 实例说明:
    1. 被transient修饰的成员变量sex,无法对数据序列化,所以输出结果中是null,因为该值是引用类型,如果是值类型就是系统默认的初始值。
    2. 恢复的对象顺序是和序列化对象一致的,这是因为反序列化文件有多个对象,恢复的顺序也是按照对象序列化时的顺序来恢复的。
    3. 如果序列化文件中的对象已经读取完了,再次readObject()会引发EOFException异常。
  • 相关阅读:
    用代码关闭冰刃(IceSword)
    .h和.cpp文件的区别
    获取其他进程的命令行(ReadProcessMemory其它进程的PPROCESS_PARAMETERS和PEB结构体)
    C#调用记事本并填写内容
    C#中比较两个对象的地址是否相同(也是引用计数的问题,和Java一样)
    JS代码的几个注意点规范
    javascript常用知识点集
    网站静态化处理—满足静态化的前后端分离(9)
    网站静态化处理—前后端分离—下(8)
    JS对文档进行操作
  • 原文地址:https://www.cnblogs.com/fwnboke/p/8529515.html
Copyright © 2011-2022 走看看