原文地址 blog.csdn.net
好像一般不用jdk提供的序列化方式,故这里仅为了解 另外Externalizable接口也可以实现序列化
1 2 3 public interface Externalizable extends java .io.Serializable { ... }
Serializable接口
自定义 writeObject 方法和 readObject 方法
如果在实现 Serializable 接口的类中自定义 writeObject 方法和 readObject 方法,则不会调用默认的方法:
先调用WriteReplace()替换,再调用WriteObject… 反射实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 public class ObjectStreamClass implements Serializable { private Method writeObjectMethod; private Method writeReplaceMethod; writeObjectMethod = getPrivateMethod(cl, "writeObject" , new Class <?>[] { ObjectOutputStream.class }, Void.TYPE); writeReplaceMethod = getInheritableMethod( cl, "writeReplace" , null , Object.class); } public class ObjectOutputStream extends OutputStream implements ObjectOutput , ObjectStreamConstants{ public final void writeObject (Object obj) throws IOException { if (enableOverride) { writeObjectOverride(obj); return ; } try { writeObject0(obj, false ); } catch (IOException ex) { if (depth == 0 ) { writeFatalException(ex); } throw ex; } } private void writeObject0 (Object obj, boolean unshared) throws IOException { Object orig = obj; Class<?> cl = obj.getClass(); ObjectStreamClass desc; for (;;) { Class<?> repCl; desc = ObjectStreamClass.lookup(cl, true ); if (!desc.hasWriteReplaceMethod() || (obj = desc.invokeWriteReplace(obj)) == null || (repCl = obj.getClass()) == cl) { break ; } cl = repCl; } if (enableReplace) { Object rep = replaceObject(obj); if (rep != obj && rep != null ) { cl = rep.getClass(); desc = ObjectStreamClass.lookup(cl, true ); } obj = rep; } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared); } } if (desc.isExternalizable() && !desc.isProxy()) { writeExternalData((Externalizable) obj); } else { writeSerialData(obj, desc); } private void writeSerialData (Object obj, ObjectStreamClass desc) throws IOException { ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout(); for (int i = 0 ; i < slots.length; i++) { ObjectStreamClass slotDesc = slots[i].desc; if (slotDesc.hasWriteObjectMethod()) { try { curContext = new SerialCallbackContext (obj, slotDesc); bout.setBlockDataMode(true ); slotDesc.invokeWriteObject(obj, this ); bout.setBlockDataMode(false ); bout.writeByte(TC_ENDBLOCKDATA); } finally { curContext.setUsed(); curContext = oldContext; if (extendedDebugInfo) { debugInfoStack.pop(); } } curPut = oldPut; } else { defaultWriteFields(obj, slotDesc); } } } }
示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 package serializable;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Student implements Serializable { private static final long serialVersionUID = 140932343675039705L ; private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "学生:" + name; } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { System.out.println("readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ System.out.println("writeObject exec..." ); } public static void main (String[] args) throws IOException, ClassNotFoundException { Student student = new Student (); student.setName("小明" ); String filePath = "/Users/dcc/Downloads/student" ; ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream (filePath)); out.writeObject(student); out.close(); ObjectInputStream in = new ObjectInputStream (new FileInputStream (filePath)); Student student1 = (Student) in.readObject(); System.out.println(student1); } }
程序输出结果:
1 2 3 writeObject exec... readObject exec... 学生:null
因为在 writeObject 方法中只打印了日志,没有序列化 name 字段,所以 readObject 方法没有反序列化出 name. 可以在自定义的 writeObject 方法和 readObject 方法中调用默认方法:
1 2 3 4 5 6 7 8 9 private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); System.out.println("writeObject exec..." ); }
修改之后 name 字段序列化和反序列化均成功,程序输出:
1 2 3 writeObject exec... readObject exec... 学生:小明
writeReplace 方法和 readResolve 方法 writeReplace 方法可以替换序列化的对象;readResolve 方法是替换反序列化的对象:
看如下代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 package serializable;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.io.Serializable;public class Student implements Serializable { private static final long serialVersionUID = 140932343675039705L ; private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "学生:" + name; } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); System.out.println("writeObject exec..." ); } private Object writeReplace () throws ObjectStreamException{ System.out.println("writeReplace exec..." ); return this ; } private Object readResolve () throws ObjectStreamException{ System.out.println("readResolve exec..." ); return this ; } public static void main (String[] args) throws IOException, ClassNotFoundException { Student student = new Student (); student.setName("小明" ); String filePath = "/Users/dcc/Downloads/student" ; ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream (filePath)); out.writeObject(student); out.close(); ObjectInputStream in = new ObjectInputStream (new FileInputStream (filePath)); Student teacher = (Student) in.readObject(); System.out.println(teacher); } }
程序运行结果:
1 2 3 4 5 writeReplace exec... writeObject exec... readObject exec... readResolve exec... 学生:小明
可以看出:writeReplace 方法是在 writeObject 方法之前执行;readResolve 方法是在 readResolve 方法之后执行。
修改上面的代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 package serializable;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.Serializable;public class Teacher implements Serializable { private static final long serialVersionUID = 4644753740588166024L ; private String teacherNo; public Teacher (String teacherNo) { this .teacherNo = teacherNo; } @Override public String toString () { return "老师:" + teacherNo; } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("Teacher readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); System.out.println("Teacher writeObject exec..." ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 public class Student implements Serializable { private static final long serialVersionUID = 140932343675039705L ; private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "学生:" + name; } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); System.out.println("writeObject exec..." ); } private Object writeReplace () throws ObjectStreamException{ System.out.println("writeReplace exec..." ); return new Teacher ("007" ); } public static void main (String[] args) throws IOException, ClassNotFoundException { Student student = new Student (); student.setName("小明" ); String filePath = "/Users/dcc/Downloads/student" ; ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream (filePath)); out.writeObject(student); out.close(); ObjectInputStream in = new ObjectInputStream (new FileInputStream (filePath)); Student student1 = (Student) in.readObject(); System.out.println(student1); } }
程序输出:
1 2 3 4 5 writeReplace exec... Teacher writeObject exec... Teacher readObject exec... Exception in thread "main" java.lang.ClassCastException: serializable.Teacher cannot be cast to serializable.Student at serializable.Student.main(Student.java:57)
可以看到序列化的小明同学 Student 对象已经被 writeReplace 方法替换成了 Teacher 对象,而且执行的是 Teacher 类中定义的 writeObject 方法和 readObject 方法。
源码,ok
反序列化处代码修改:
1 2 3 ObjectInputStream in = new ObjectInputStream (new FileInputStream (filePath));Teacher teacher = (Teacher) in.readObject();System.out.println(teacher);
程序输出结果:
1 2 3 4 writeReplace exec... Teacher writeObject exec... Teacher readObject exec... 老师:007
我们在 Student 类中增加 readResolve 方法:
1 2 3 4 private Object readResolve () throws ObjectStreamException{ System.out.println("readResolve exec..." ); return new Teacher ("001" ); }
此时反序列化得到的老师对象仍是 “老师: 007” 而不是“老师: 001”,因为反序列化出的是 Teacher 对象,不会调用 Student 的 readResolve 方法。
我们接着在 Teacher 类中添加 readResolve 方法:
1 2 3 4 private Object readResolve () throws ObjectStreamException{ System.out.println("Teacher readResolve exec..." ); return new Teacher ("001" ); }
此时序列化得到的老师对象才是 “老师: 001”。
我们把 Student 和 Teacher 类中的 writeObject 方法、 readObject 方法、writeReplace 方法和、readResolve 方法四种方法都补齐,看一下调用顺序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 package serializable;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.io.Serializable;public class Teacher implements Serializable { private static final long serialVersionUID = 4644753740588166024L ; private String teacherNo; public Teacher (String teacherNo) { this .teacherNo = teacherNo; } @Override public String toString () { return "老师:" + teacherNo; } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("Teacher readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); System.out.println("Teacher writeObject exec..." ); } private Object writeReplace () throws ObjectStreamException { System.out.println("Teacher writeReplace exec..." ); return this ; } private Object readResolve () throws ObjectStreamException{ System.out.println("Teacher readResolve exec..." ); return new Teacher ("001" ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 package serializable;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.ObjectInputStream;import java.io.ObjectOutputStream;import java.io.ObjectStreamException;import java.io.Serializable;public class Student implements Serializable { private static final long serialVersionUID = 140932343675039705L ; private String name; public String getName () { return name; } public void setName (String name) { this .name = name; } @Override public String toString () { return "学生:" + name; } private void readObject (ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); System.out.println("readObject exec..." ); } private void writeObject (ObjectOutputStream out) throws IOException{ out.defaultWriteObject(); System.out.println("writeObject exec..." ); } private Object writeReplace () throws ObjectStreamException{ System.out.println("writeReplace exec..." ); return new Teacher ("007" ); } private Object readResolve () throws ObjectStreamException{ System.out.println("readResolve exec..." ); return new Teacher ("001" ); } public static void main (String[] args) throws IOException, ClassNotFoundException { Student student = new Student (); student.setName("小明" ); String filePath = "/Users/dcc/Downloads/student" ; ObjectOutputStream out = new ObjectOutputStream (new FileOutputStream (filePath)); out.writeObject(student); out.close(); ObjectInputStream in = new ObjectInputStream (new FileInputStream (filePath)); Teacher teacher = (Teacher) in.readObject(); System.out.println(teacher); } }
程序输出结果:
1 2 3 4 5 6 writeReplace exec... Teacher writeReplace exec... Teacher writeObject exec... Teacher readObject exec... Teacher readResolve exec... 老师:001