资讯专栏INFORMATION COLUMN

java序列化,看这篇就够了

番茄西红柿 / 623人阅读

摘要:序列化机制使得对象可以脱离程序的运行而独立存在。普通序列化接口是一个标记接口,不用实现任何方法。如果此对象已经序列化过,则直接输出编号即可。图示上述序列化过程。

一、序列化的含义、意义及使用场景二、序列化实现的方式1、Serializable1.1 普通序列化1.2 成员是引用的序列化1.3 同一对象序列化多次的机制1.4 java序列化算法潜在的问题1.5 可选的自定义序列化2、Externalizable:强制自定义序列化3、两种序列化对比三、序列化版本号serialVersionUID四、总结

一、序列化的含义、意义及使用场景
  • 序列化:将对象写入到IO流中

  • 反序列化:从IO流中恢复对象

  • 意义:序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。

  • 使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。

    二、序列化实现的方式

    如果需要将某个对象保存到磁盘上或者通过网络传输,那么这个类应该实现Serializable接口或者Externalizable接口之一。

    1、Serializable

    1.1 普通序列化

    Serializable接口是一个标记接口,不用实现任何方法。一旦实现了此接口,该类的对象就是可序列化的。

    1. 序列化步骤:

    • 步骤一:创建一个ObjectOutputStream输出流;

    • 步骤二:调用ObjectOutputStream对象的writeObject输出可序列化对象。

      public class Person implements Serializable {
        private String name;
        private int age;
        //我不提供无参构造器
        public Person(String name, int age) {
            this.name = name;
            this.age = age;
        }

        @Override
        public String toString() {
            return "Person{" +
                    "name=" + name +  +
                    ", age=" + age +
                    };
        }
      }

      public class WriteObject {
        public static void main(String[] args) {
            try (//创建一个ObjectOutputStream输出流
                 ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("object.txt"))) {
                //将对象序列化到文件s
                Person person = new Person("9龙"23);
                oos.writeObject(person);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
      }

      1. 反序列化步骤:

      • 步骤一:创建一个ObjectInputStream输入流;

      • 步骤二:调用ObjectInputStream对象的readObject()得到序列化的对象。

        我们将上面序列化到person.txt的person对象反序列化回来

        public class Person implements Serializable {
          private String name;
          private int age;
          //我不提供无参构造器
          public Person(String name, int age) {
              System.out.println("反序列化,你调用我了吗?");
              this.name = name;
              this.age = age;
          }

          @Override
          public String toString() {
              return "Person{" +
                      "name=" + name +  +
                      ", age=" + age +
                      };
          }
        }

        public class ReadObject {
          public static void main(String[] args) {
              try (//创建一个ObjectInputStream输入流
                   ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.txt"))) {
                  Person brady = (Person) ois.readObject();
                  System.out.println(brady);
              } catch (Exception e) {
                  e.printStackTrace();
              }
          }
        }
        //输出结果
        //Person{name=9龙, age=23}

        waht);

        1.2 成员是引用的序列化

        如果一个可序列化的类的成员不是基本类型,也不是String类型,那这个引用类型也必须是可序列化的;否则,会导致此类不能序列化。

        看例子,我们新增一个Teacher类。将Person去掉实现Serializable接口代码。

        public class Person{
            //省略相关属性与方法
        }
        public class Teacher implements Serializable {

            private String name;
            private Person person;

            public Teacher(String name, Person person) {
                this.name = name;
                this.person = person;
            }

             public static void main(String[] args) throws Exception {
                try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"))) {
                    Person person = new Person("路飞"20);
                    Teacher teacher = new Teacher("雷利", person);
                    oos.writeObject(teacher);
                }
            }
        }

        我们看到程序直接报错,因为Person类的对象是不可序列化的,这导致了Teacher的对象不可序列化

        1.3 同一对象序列化多次的机制

        同一对象序列化多次,会将这个对象序列化多次吗?答案是否定的。

        public class WriteTeacher {
            public static void main(String[] args) throws Exception {
                try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("teacher.txt"))) {
                    Person person = new Person("路飞"20);
                    Teacher t1 = new Teacher("雷利", person);
                    Teacher t2 = new Teacher("红发香克斯", person);
                    //依次将4个对象写入输入流
                    oos.writeObject(t1);
                    oos.writeObject(t2);
                    oos.writeObject(person);
                    oos.writeObject(t2);
                }
            }
        }

        依次将t1、t2、person、t2对象序列化到文件teacher.txt文件中。

        注意:反序列化的顺序与序列化时的顺序一致

        public class ReadTeacher {
            public static void main(String[] args) {
                try (ObjectInputStream ois = new ObjectInputStream(new FileInputStream("teacher.txt"))) {
                    Teacher t1 = (Teacher) ois.readObject();
                    Teacher t2 = (Teacher) ois.readObject();
                    Person p = (Person) ois.readObject();
                    Teacher t3 = (Teacher) ois.readObject();
                    System.out.println(t1 == t2);
                    System.out.println(t1.getPerson() == p);
                    System.out.println(t2.getPerson() == p);
                    System.out.println(t2 == t3);
                    System.out.println(t1.getPerson() == t2.getPerson());
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        //输出结果
        //false
        //true
        //true
        //true
        //true

        从输出结果可以看出,Java序列化同一对象,并不会将此对象序列化多次得到多个对象。

        • Java序列化算法

          1. 所有保存到磁盘的对象都有一个序列化编码号

          2. 当程序试图序列化一个对象时,会先检查此对象是否已经序列化过,只有此对象从未(在此虚拟机)被序列化过,才会将此对象序列化为字节序列输出。

          3. 如果此对象已经序列化过,则直接输出编号即可。

            图示上述序列化过程。

          1.4 java序列化算法潜在的问题

          由于java序利化算法不会重复序列化同一个对象,只会记录已序列化对象的编号。如果序列化一个可变对象(对象内的内容可更改)后,更改了对象内容,再次序列化,并不会再次将此对象转换为字节序列,而只是保存序列化编号。

          public class WriteObject {
              public static 

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/7113.html

相关文章

  • java列化看这篇就够了

    摘要:序列化机制使得对象可以脱离程序的运行而独立存在。普通序列化接口是一个标记接口,不用实现任何方法。如果此对象已经序列化过,则直接输出编号即可。图示上述序列化过程。一、序列化的含义、意义及使用场景二、序列化实现的方式1、Serializable1.1 普通序列化1.2 成员是引用的序列化1.3 同一对象序列化多次的机制1.4 java序列化算法潜在的问题1.5 可选的自定义序列化2、Extern...

    Hydrogen 评论0 收藏0
  • 你真的完全了解Java动态代理吗?看这篇就够了

    摘要:动态地代理,可以猜测一下它的含义,在运行时动态地对某些东西代理,代理它做了其他事情。所以动态代理的内容重点就是这个。所以下一篇我们来细致了解下的到底是怎么使用动态代理的。 之前讲了《零基础带你看Spring源码——IOC控制反转》,本来打算下一篇讲讲Srping的AOP的,但是其中会涉及到Java的动态代理,所以先单独一篇来了解下Java的动态代理到底是什么,Java是怎么实现它的。 ...

    haitiancoder 评论0 收藏0
  • java列化看这篇就够了

    摘要:序列化机制使得对象可以脱离程序的运行而独立存在。普通序列化接口是一个标记接口,不用实现任何方法。如果此对象已经序列化过,则直接输出编号即可。图示上述序列化过程。一、序列化的含义、意义及使用场景二、序列化实现的方式1、Serializable1.1 普通序列化1.2 成员是引用的序列化1.3 同一对象序列化多次的机制1.4 java序列化算法潜在的问题1.5 可选的自定义序列化2、Extern...

    番茄西红柿 评论0 收藏0
  • 线程池?面试?看这篇就够了

    摘要:手动创建执行线程存在以上问题,而线程池就是用来解决这些问题的。线程池详解上面我们已经知道了线程池的作用,而对于这样一个好用,重要的工具,当然已经为我们提供了实现,这也是本篇文章的重点。,线程池一旦空闲超过时间,线程都将被回收。 showImg(https://segmentfault.com/img/remote/1460000018476903); 本文原创地址,我的博客:https...

    antz 评论0 收藏0
  • Lombok 看这篇就够了

    摘要:注解在类上为类提供一个全参的构造方法,加了这个注解后,类中不提供默认构造方法了。这个注解用在类上,使用类中所有带有注解的或者带有修饰的成员变量生成对应的构造方法。 转载请注明原创地址:http://www.54tianzhisheng.cn/2018/01/07/lombok/ showImg(http://ohfk1r827.bkt.clouddn.com/blog/180107/7...

    LeanCloud 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<