Java序列化

学习Java的同学注意了!!! 
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:523047986  我们一起学Java!

一、序列化

  • 序列化定义:序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。
  • 目的:
    • 以某种存储形式使自定义对象持久化
    • 将对象从一个地方传递到另一个地方

二、Java序列化

  • 一个对象能够序列化的前提是实现Serializable接口。Serializable接口没有方法,更像是个标记。有了这个标记的Class就能被序列化机制处理。如下:
  • [java] view
    plain
     copy

    1. class myPoint implements Serializable{  
    2. }  

     

  • JAVA反序列化不会调用任何构造器
  • 序列化的控制:Externalizable。读写都交给你
    • 要在方法writeExternal写入序列化的参数
    • 要在方法readExternal读取反序列化的值
    • 要有默认的构造方法(readExternal执行完成,再执行默认的构造器)
    • [java] view
      plain
       copy

      1. void writeExternal(ObjectOutput out) throws IOException;  
      2. void readExternal(ObjectInput in) throws IOException,ClassNotFoundException;  
      3. public class Point implements Externalizable {  
      4.     private int a;  
      5.     private int b;  
      6.     public Point(int a, int b) {  
      7.         this.a = a;  
      8.         this.b = b;  
      9.     }  
      10.     public Point() {  
      11.     }  
      12.     public String toString() {  
      13.         return a + " , " + b;  
      14.     }  
      15.       
      16.     public void writeExternal(ObjectOutput out) throws IOException {  
      17.         out.write(a);  
      18.         out.write(b);  
      19.     }  
      20.     public void readExternal(ObjectInput in) throws IOException,  
      21.             ClassNotFoundException {  
      22.         a = in.read();  
      23.         b = in.read();  
      24.     }  
      25.     public static void main(String[] args) throws IOException,  
      26.             ClassNotFoundException {  
      27.         String file = "d://1.txt";  
      28.         Point p = new Point(12);  
      29.         System.out.println(p);  
      30.         FileOutputStream fos = new FileOutputStream(file);  
      31.         ObjectOutputStream oos = new ObjectOutputStream(fos);  
      32.         oos.writeObject(p);  
      33.         FileInputStream fis = new FileInputStream(file);  
      34.         ObjectInputStream ois = new ObjectInputStream(fis);  
      35.         Point pp = (Point) ois.readObject();  
      36.         System.out.println(pp);  
      37.     }  
      38. }  

       

    • transient关键字 关闭序列化自动进行。
    • 不管你选择了哪种序列化形式,都要为自己编写的每个可序列化的类声明一个显示的序列版本UID(serial version UID)

三、序列化的问题

effective Java中列举出了java序列化要注意的一些问题:

  1. 谨慎地设计实现Serializable接口
    • 实现发布了就是一种承诺
    • 如果一个类是为继承设计的,在‘允许子类实现Serializable接口’与‘禁止子类实现Serializable接口’取一个折中的方案是:提供一个可访问的无参构造器
  2. 保护性地编写 readObject()方法,因为readObject()是构建实例的入口。
    • 不保护可能出现 构建了不满足要求的 实例
  3. 考虑自定义的序列化形式
    • 逻辑内容 与 物理表示法
    • 如果一个对象的 ‘物理表示法’等同于它的‘逻辑内容’,可能就适用于使用默认的序列化形式。
    • 如果有更好的 ‘物理表示法’在表示‘逻辑内容’则可以自定义序列化形式。
    • [java] view
      plain
       copy

      1. public class StringList implements Serializable {  
      2.     private transient int size = 0;  
      3.     private transient Entity head = null;  
      4.     public final void add(String str) {  
      5.         // …  
      6.     }  
      7.     private static class Entity {  
      8.         String data;  
      9.         Entity next;  
      10.         Entity previous;  
      11.     }  
      12.     private void writeObject(ObjectOutputStream s) throws IOException {  
      13.         s.defaultWriteObject();  
      14.         s.write(size);  
      15.         for (Entity e = head; e != null; e = e.next) {  
      16.             s.writeObject(e.data);  
      17.         }  
      18.     }  
      19.     private void readObject(ObjectInputStream s) throws IOException,  
      20.             ClassNotFoundException {  
      21.         s.defaultReadObject();  
      22.         int num = s.read();  
      23.         for (int i = 0; i < num; i++) {  
      24.             this.add((String) s.readObject());  
      25.         }  
      26.     }  
      27. }  

       

四、序列化代理模式

    序列化机制提供的钩子函数有:

       writeReplace writeObject  readObject  readResolve

  • writeReplace:序列化的时候替换所要序列化的对象。
  • writeObject:写入序列化的对象
  • readObject:读取序列化的对象
  • readResolve:最后返回序列化对象
    1. import java.io.InvalidObjectException;  
    2. import java.io.ObjectInputStream;  
    3. import java.io.Serializable;  
    4. import java.util.Date;  
    5. public final class Period implements Serializable {  
    6.     private static final long serialVersionUID = 100L;  
    7.     private final Date start;  
    8.     private final Date end;  
    9.     public Period(Date start, Date end) {  
    10.         this.start = new Date(start.getTime());  
    11.         this.end = new Date(end.getTime());  
    12.         if (this.start.compareTo(this.end) > 0) {  
    13.             throw new IllegalArgumentException(start + " after " + end);  
    14.         }  
    15.     }  
    16.     public Date start() {  
    17.         return new Date(start.getTime());  
    18.     }  
    19.     public Date end() {  
    20.         return new Date(end.getTime());  
    21.     }  
    22.     public String toString() {  
    23.         return start + " – " + end;  
    24.     }  
    25.     // 不给  
    26.     private Object writeReplace() {  
    27.         return new SerializationProxy(this);  
    28.     }  
    29.     private void readObject(ObjectInputStream stream)  
    30.             throws InvalidObjectException {  
    31.         throw new InvalidObjectException("proxy request");  
    32.     }  
    33.     private static class SerializationProxy implements Serializable {  
    34.         private final Date start;  
    35.         private final Date end;  
    36.         SerializationProxy(Period p) {  
    37.             this.start = p.start;  
    38.             this.end = p.end;  
    39.         }  
    40.         private Object readResolve() {  
    41.             return new Period(start, end);  
    42.         }  
    43.         private static final long serialVersionUID = 1000L;  
    44.     }  
    45. }   

五、序列化算法

  1. 将对象实例相关的类元数据输出。
  2. 递归地输出类的超类描述直到不再有超类。
  3. 类元数据完了以后,开始从最顶层的超类开始输出对象实例的实际数据值。
  4. 从上至下递归输出实例的数据

学习Java的同学注意了!!! 
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群,群号码:523047986  我们一起学Java!

IT文库 » Java序列化
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址