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

    什么叫做对象的序列化?

      一个对象产生之后实际上就在内存中开辟了一个存储空间,方便存储信息。

      对象的序列化就是将一个对象变成二进制的数据流的一种方法,通过对象的序列化可以方便的实现对象的存储和传输。如果一个类的对象需要被序列化,则该类必须实现Serializable接口,该接口的定义如下:

    1 public interface Serializable {
    2     
    3 }

      Serializable接口中没有任何方法,只表示该类有这样具备这样一种能力,属于标识接口。下面的一个Student因为实现了Serializable接口,所以它就是可序列化的了:

     1 package io.Serializable;
     2 
     3 import java.io.Serializable;
     4 
     5 public class Student implements Serializable {
     6     private String name;
     7     private int age;
     8 
     9     public Student(String name, int age) {
    10         super();
    11         this.name = name;
    12         this.age = age;
    13     }
    14 
    15     public String getName() {
    16         return name;
    17     }
    18 
    19     public void setName(String name) {
    20         this.name = name;
    21     }
    22 
    23     public int getAge() {
    24         return age;
    25     }
    26 
    27     public void setAge(int age) {
    28         this.age = age;
    29     }
    30 
    31     @Override
    32     public String toString() {
    33         return "Student [name=" + name + ", age=" + age + "]";
    34     }
    35 
    36 }

      以上的代码仅仅是实现了Serializable接口,其他部分并没有任何改变,以上的类产生的对象就是可序列化(二进制比特流)的了。

    如果要进行对象的序列化必须依靠两个类:

    ObjectInputStream和ObjectOutputStream

     serialVersionUID

      在对对象进行序列化和反序列化的时候要考虑到JDK版本的问题,如果序列化的JDK版本和反序列化的JDK版本不统一就会抛出异常。所以在对象序列化的操作中引入了一个serialVersionUID的常量。可以通过此常量验证版本的一致性。在进行反序列化的操作时,JVM会把传来的字节流中的serialVersionUID与本地响应实体(类)的serialVersionUID进行比较,如果相同就认为是一致的,可以进行反序列化的操作,否则就会抛出序列化版本不一致的异常。

      如果使用Eclipse进行编写,如果没有指定serialVersionUID则会出现一些警告信息,如图:

      按照Eclipse的提示,我们加上这个常量,这样这个类的设计就完成了。

    对象的序列化和反序列化:

     1 package io.Serializable;
     2 
     3 import java.io.File;
     4 import java.io.FileInputStream;
     5 import java.io.FileNotFoundException;
     6 import java.io.FileOutputStream;
     7 import java.io.IOException;
     8 import java.io.ObjectInputStream;
     9 import java.io.ObjectOutputStream;
    10 
    11 public class SerializableDemo {
    12 
    13     public static void main(String[] args) {
    14 
    15         File file = new File("E:" + File.separator + "tmp" + File.separator
    16                 + "stu.obj"); // 保存路径
    17         try {
    18             ObjectOutputStream oos = new ObjectOutputStream(
    19                     new FileOutputStream(file));
    20 
    21             Student[] students = { new Student("张三", 12),
    22                     new Student("李四", 15), new Student("王五", 18) };
    23             oos.writeObject(students); // 直接写入一个对象数组,因为数组也是对象
    24             oos.close();
    25 
    26             ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
    27                     file));
    28             Student[] stus = (Student[]) ois.readObject();
    29             ois.close();
    30 
    31             for (Student student : stus) {
    32                 System.out.println(student);
    33             }
    34 
    35         } catch (FileNotFoundException e) {
    36             e.printStackTrace();
    37         } catch (IOException e) {
    38             e.printStackTrace();
    39         } catch (ClassNotFoundException e) {
    40             e.printStackTrace();
    41         }
    42 
    43     }
    44 
    45 }

      运行结果:

     Externalizable接口

      被Serializable接口声明的类的对象的内容都能够被序列化,如果现在用户希望可以自己制定序列化的内容,则可以让一个类实现Externalizable接口,该接口的定义如下:

    1 public interface Externalizable extends Serializable {
    2     public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException;
    3     public void writeExternal(ObjectOutput out)throws IOException;                  
    4 }

     利用此接口修改之前的程序:

     1 package io.Serializable;
     2 
     3 import java.io.Externalizable;
     4 import java.io.IOException;
     5 import java.io.ObjectInput;
     6 import java.io.ObjectOutput;
     7 
     8 public class Student implements Externalizable {
     9     private String name;
    10     private int age;
    11 
    12     public Student(String name, int age) {
    13         super();
    14         this.name = name;
    15         this.age = age;
    16     }
    17 
    18     public String getName() {
    19         return name;
    20     }
    21 
    22     public void setName(String name) {
    23         this.name = name;
    24     }
    25 
    26     public int getAge() {
    27         return age;
    28     }
    29 
    30     public void setAge(int age) {
    31         this.age = age;
    32     }
    33 
    34     @Override
    35     public String toString() {
    36         return "Student [name=" + name + ", age=" + age + "]";
    37     }
    38 
    39     @Override
    40     public void readExternal(ObjectInput in) throws IOException,
    41             ClassNotFoundException {
    42         this.name = (String) in.readObject();    //读取属性
    43         this.age = in.readInt();
    44     }
    45 
    46     @Override
    47     public void writeExternal(ObjectOutput out) throws IOException {
    48         out.writeObject(this.name);    //保存属性
    49         out.writeInt(this.age);
    50     }
    51 
    52 }
     1 package io.Serializable;
     2 
     3 import java.io.File;
     4 import java.io.FileInputStream;
     5 import java.io.FileNotFoundException;
     6 import java.io.FileOutputStream;
     7 import java.io.IOException;
     8 import java.io.ObjectInputStream;
     9 import java.io.ObjectOutputStream;
    10 
    11 public class SerializableDemo {
    12 
    13     public static void main(String[] args) {
    14 
    15         File file = new File("E:" + File.separator + "tmp" + File.separator
    16                 + "stu.obj"); // 保存路径
    17         try {
    18             ObjectOutputStream oos = new ObjectOutputStream(
    19                     new FileOutputStream(file));
    20 
    21             Student[] students = { new Student("张三", 12),
    22                     new Student("李四", 15), new Student("王五", 18) };
    23             oos.writeObject(students); // 直接写入一个对象数组,因为数组也是对象
    24             oos.close();
    25 
    26             
    27             ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
    28                     file));
    29             Student[] stus = (Student[]) ois.readObject();
    30             ois.close();
    31 
    32             for (Student student : stus) {
    33                 System.out.println(student);
    34             }
    35 
    36         } catch (FileNotFoundException e) {
    37             e.printStackTrace();
    38         } catch (IOException e) {
    39             e.printStackTrace();
    40         } catch (ClassNotFoundException e) {
    41             e.printStackTrace();
    42         }
    43 
    44     }
    45 
    46 }

      运行结果:

      在使用Externalizable接口的时候需要原有的类中有无参构造,在Student类中加入无参构造后一切正常了!此外在Externalizable接口中也可以自定义哪些属性需要序列化,见以下代码:

     1     @Override
     2     public void readExternal(ObjectInput in) throws IOException,
     3             ClassNotFoundException {
     4         this.name = (String) in.readObject();    //读取属性
     5 //        this.age = in.readInt();
     6     }
     7 
     8     @Override
     9     public void writeExternal(ObjectOutput out) throws IOException {
    10         out.writeObject(this.name);    //保存属性
    11 //        out.writeInt(this.age);
    12     }

      以上代码在运行的时候age属性将不会序列化!

    transient关键字:

      在序列化对象的时候如果不需要某个属性被序列化可以使用transient关键字进行修饰。如此一来Externalizable接口就变得毫无用途。

    1 private  transient int age;    //age属性不会被序列化

      运行结果:

      由此可见Externalizable接口的功能完全可以由Serializable接口和transient关键字的组合来取代!

  • 相关阅读:
    直接插入排序
    归并排序
    正则问题
    九宫重排
    java合并两个集合并通过stream流构建响应结果
    企业微信扫码登录
    docker安装es
    docker安装nacos随记
    解决docker安装mysql8.0无法远程连接问题
    java分析工具10:jvm测试与调优
  • 原文地址:https://www.cnblogs.com/happyfans/p/4230480.html
Copyright © 2011-2022 走看看