序列化Serializable和Externalizable的区别(一)

2015-01-27 14:01:17 · 作者: · 浏览: 42
大家都知道Serializable是一个mark interface,告诉JVM这个对象可以被转换成二进制流来传输.
但是Serializable与Externalizable的转换二进制流的过程是不一样的.
Serializable 在我们实现这个接口的时候,我们可以使用4个私有方法来控制序列化的过程:
我们来看一个例子:
Java代码 收藏代码
  1. public class FooImpl implements java.io.Serializable{
  2. private String message;
  3. public String getFoo() {
  4. return message;
  5. }
  6. public void setMessage(String message) {
  7. this.message = message;
  8. }
  9. private void writeObject(java.io.ObjectOutputStream out) throws IOException {
  10. System.out.println("writeObject invoked");
  11. out.writeObject(this.message == null ? "hohohahaha" : this.message);
  12. }
  13. private void readObject(java.io.ObjectInputStream in) throws IOException,
  14. ClassNotFoundException {
  15. System.out.println("readObject invoked");
  16. this.message = (String) in.readObject();
  17. System.out.println("got message:" + message);
  18. }
  19. private Object writeReplace() throws ObjectStreamException {
  20. System.out.println("writeReplace invoked");
  21. return this;
  22. }
  23. private Object readResolve() throws ObjectStreamException {
  24. System.out.println("readResolve invoked");
  25. return this;
  26. }
  27. public Object serialize() throws IOException, ClassNotFoundException {
  28. ByteArrayOutputStream baos = new ByteArrayOutputStream();
  29. ObjectOutputStream oos = new ObjectOutputStream(baos);
  30. oos.writeObject(this);
  31. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
  32. ObjectInputStream ois = new ObjectInputStream(bais);
  33. return ois.readObject();
  34. }
  35. public static void main(String[] args) throws IOException,
  36. ClassNotFoundException {
  37. FooImpl fooimpl = new FooImpl();
  38. fooimpl.serialize();
  39. }
    我们运行这段代码看到的debug信息:
    writeReplace invoked
    writeObject invoked
    readObject invoked
    readResolve invoked


    当进行序列化的时候:
    首先JVM会先调用writeReplace方法,在这个阶段,我们可以进行张冠李戴,将需要进行序列化的对象换成我们指定的对象.
    跟着JVM将调用writeObject方法,来将对象中的属性一个个进行序列化,我们可以在这个方法中控制住哪些属性需要序列化.

    当反序列化的时候:
    JVM会调用readObject方法,将我们刚刚在writeObject方法序列化好的属性,反序列化回来.
    然后在readResolve方法中,我们也可以指定JVM返回我们特定的对象(不是刚刚序列化回来的对象).

    注意到在writeReplace和readResolve,我们可以严格控制singleton的对象,在同一个JVM中完完全全只有唯一的对象,控制不让singleton对象产生副本.


    Externalizable 是一个有实际方法需要实现的interface,包括writeExternal和readExternal:
    Java代码 收藏代码
    1. public class FooImpl implements java.io.Externalizable {
    2. private String message;
    3. public String getFoo() {
    4. return message;
    5. }
    6. public void setMessage(String message) {
    7. this.message = message;
    8. }
    9. private Object writeReplace() throws ObjectStreamException {
    10. System.out.println("writeReplace invoked");
    11. return this;
    12. }
    13. private Object readResolve() throws ObjectStreamException {
    14. System.out.println("readResolve invoked");
    15. return this;
    16. }
    17. public Object serialize() throws IOException, ClassNotFoundException {
    18. ByteArrayOutputStream baos = new ByteArrayOutputStream();
    19. ObjectOutputStream oos = new ObjectOutputStream(baos);
    20. oos.writeObject(this);
    21. ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
    22. ObjectInputStream ois = new ObjectInputStream(bais);
    23. return ois.readObject();
    24. }
    25. public void readExternal(ObjectInput arg0) throws IOException,
    26. ClassNotFoundException {
    27. System.out.println("readExternal invoked");
    28. Object obj = arg0.readObject();
    29. }
    30. public void writeExternal(ObjectOutput arg0) throws IOException {
    31. System.out.println("writeExternal invoked");
    32. arg0.writeObject("Hello world");
    33. }
    34. public static void main(S