首页 > 开发 > Java > 正文

Java 序列化详解及简单实现实例

2024-07-13 10:05:14
字体:
来源:转载
供稿:网友

一、序列化

序列化定义:序列化是将对象状态转换为可保持或传输的格式的过程。与序列化相对的是反序列化,它将流转换为对象。这两个过程结合起来,可以轻松地存储和传输数据。

目的:

  1. 以某种存储形式使自定义对象持久化
  2. 将对象从一个地方传递到另一个地方

二、java/96470.html">java/191614.html">Java序列化

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

class myPoint implements Serializable{ }  

JAVA反序列化不会调用任何构造器

序列化的控制:Externalizable。读写都交给你

  1. 要在方法writeExternal写入序列化的参数
  2. 要在方法readExternal读取反序列化的值
  3. 要有默认的构造方法(readExternal执行完成,再执行默认的构造器)
void writeExternal(ObjectOutput out) throws IOException; void readExternal(ObjectInput in) throws IOException,ClassNotFoundException; public class Point implements Externalizable {   private int a;   private int b;   public Point(int a, int b) {     this.a = a;     this.b = b;   }   public Point() {   }   public String toString() {     return a + " , " + b;   }      public void writeExternal(ObjectOutput out) throws IOException {     out.write(a);     out.write(b);   }   public void readExternal(ObjectInput in) throws IOException,       ClassNotFoundException {     a = in.read();     b = in.read();   }   public static void main(String[] args) throws IOException,       ClassNotFoundException {     String file = "d://1.txt";     Point p = new Point(1, 2);     System.out.println(p);     FileOutputStream fos = new FileOutputStream(file);     ObjectOutputStream oos = new ObjectOutputStream(fos);     oos.writeObject(p);     FileInputStream fis = new FileInputStream(file);     ObjectInputStream ois = new ObjectInputStream(fis);     Point pp = (Point) ois.readObject();     System.out.println(pp);   } }  
  1. transient关键字 关闭序列化自动进行。
  2. 不管你选择了哪种序列化形式,都要为自己编写的每个可序列化的类声明一个显示的序列版本UID(serial version UID)

三、序列化的问题

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

1.谨慎地设计实现Serializable接口

  1. 实现发布了就是一种承诺
  2. 如果一个类是为继承设计的,在‘允许子类实现Serializable接口'与‘禁止子类实现Serializable接口'取一个折中的方案是:提供一个可访问的无参构造器

2.保护性地编写 readObject()方法,因为readObject()是构建实例的入口。

不保护可能出现 构建了不满足要求的 实例

3.考虑自定义的序列化形式

  1. 逻辑内容 与 物理表示法
  2. 如果一个对象的 ‘物理表示法'等同于它的‘逻辑内容',可能就适用于使用默认的序列化形式。
  3. 如果有更好的 ‘物理表示法'在表示‘逻辑内容'则可以自定义序列化形式。
public class StringList implements Serializable {   private transient int size = 0;   private transient Entity head = null;   public final void add(String str) {     // ...   }   private static class Entity {     String data;     Entity next;     Entity previous;   }   private void writeObject(ObjectOutputStream s) throws IOException {     s.defaultWriteObject();     s.write(size);     for (Entity e = head; e != null; e = e.next) {       s.writeObject(e.data);     }   }   private void readObject(ObjectInputStream s) throws IOException,       ClassNotFoundException {     s.defaultReadObject();     int num = s.read();     for (int i = 0; i < num; i++) {       this.add((String) s.readObject());     }   } }  

四、序列化代理模式

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

       writeReplace writeObject  readObject  readResolve

  1. writeReplace:序列化的时候替换所要序列化的对象。
  2. writeObject:写入序列化的对象
  3. readObject:读取序列化的对象
  4. readResolve:最后返回序列化对象
import java.io.InvalidObjectException; import java.io.ObjectInputStream; import java.io.Serializable; import java.util.Date; public final class Period implements Serializable {   private static final long serialVersionUID = 100L;   private final Date start;   private final Date end;   public Period(Date start, Date end) {     this.start = new Date(start.getTime());     this.end = new Date(end.getTime());     if (this.start.compareTo(this.end) > 0) {       throw new IllegalArgumentException(start + " after " + end);     }   }   public Date start() {     return new Date(start.getTime());   }   public Date end() {     return new Date(end.getTime());   }   public String toString() {     return start + " - " + end;   }   // 不给   private Object writeReplace() {     return new SerializationProxy(this);   }   private void readObject(ObjectInputStream stream)       throws InvalidObjectException {     throw new InvalidObjectException("proxy request");   }   private static class SerializationProxy implements Serializable {     private final Date start;     private final Date end;     SerializationProxy(Period p) {       this.start = p.start;       this.end = p.end;     }     private Object readResolve() {       return new Period(start, end);     }     private static final long serialVersionUID = 1000L;   } }  

五、序列化算法

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

 感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!


注:相关教程知识阅读请移步到JAVA教程频道。
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表