第 18 章 – java IO系统 – 序列化 与反序列化 – Externalizable接口的替代,static字段不会序列化(p597)
第 18 章 – java IO系统 – 序列化 与反序列化 – Externalizable接口的替代,static字段不会序列化(p597)
一. 如果不想实现Externalizable接口(为什么不想?难道是因为接口方法是public的,谁都可以调用么?),
可以使用下面方法替代:
1. 对象依然是要实现Serializable接口.
2. 为对象添加下面的两个方法,注意方法由private修饰,方法的签名必须和下面的一样.
private void writeObject(ObjectOutputStream stream) throws IOException private void readObject(ObjectInputStream strea) throws IOException,ClassNotFoundException
这里的设计比较奇怪和混乱,因为private方法也能被调用了,Thinking in Java 作者对此进行了批评.
3. 在有了上面的两个方法后,对象 序列化 时,ObjectOutputStream.writeObject()方法调用时,会检查
所传递的Serializable对象看看是否有上面的writeObject方法,如果有,则跳出正常的序列化过程,
改成调用Serializable对象的writeObject方法.反序列化时ObjectInputStream的readObject与之
类似.
另外,可以在2中的writeObject中调用defaultWriteObject()来执行默认的序列化过程(默认的writeObject).
下面的示例代码中,采用这种替代方式,使用了defaultWriteObject()来处理默认的序列化操作,而对于由transient
修饰的字段则额外进行了处理.
package io; import java.io.*; public class SerialCtl implements Serializable { private static final long serialVersionUID = 3587339559164696206L; private String a; private transient String b; public SerialCtl(String aa, String bb) { a = "Not Transient: " + aa; b = "Transient: " + bb; } public String toString() { return a + "\n" + b; } //这个方法签名,必须是这样的. private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); //可以按照默认的序列化程序进行 stream.writeObject(b); } //这个方法签名,必须是这样的. private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); b = (String) stream.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException { SerialCtl sc = new SerialCtl("Test1", "Test2"); System.out.println("Before:\n" + sc); ByteArrayOutputStream buf = new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(buf); o.writeObject(sc); // Now get it back: ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(buf.toByteArray())); SerialCtl sc2 = (SerialCtl) in.readObject(); System.out.println("\nAfter:\n" + sc2); } }
二. 静态字段不会初始化. 在一个地方序列化了对象,在另一个地方反序列化时,static字段值恢复成类定义是的默认值.
示例.首先,执行下面的类生成序列化文件:
package io; import java.io.*; class Student1 implements Serializable { private static final long serialVersionUID = 1L; private String name; private transient String password; private static int count = 0; public Student1(String name, String password) { System.out.println("调用Student的带参的构造方法"); this.name = name; this.password = password; count++; } public String toString() { return "人数: " + count + " 姓名: " + name + " 密码: " + password; } } public class TestStaticSerialable1 { public static void main(String args[]) { try { FileOutputStream fos = new FileOutputStream("test.obj"); ObjectOutputStream oos = new ObjectOutputStream(fos); Student1 s1 = new Student1("张三", "12345"); Student1 s2 = new Student1("王五", "54321"); oos.writeObject(s1); oos.writeObject(s2); oos.close(); FileInputStream fis = new FileInputStream("test.obj"); ObjectInputStream ois = new ObjectInputStream(fis); Student1 s3 = (Student1) ois.readObject(); Student1 s4 = (Student1) ois.readObject(); //人数: 2 姓名: 王五 密码: null //这里人数是2,看起来好像静态变量序列化了,其实是因为这里反序列化时,Class文件已经加载了导致的. //假如在另外一个类中反序列化,则重新加载Student的Class文件,然后人数字段就变成初始值0了. //参见下面TestStaticSerialable类 System.out.println(s3); System.out.println(s4); ois.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } } /** * 输出: * 调用Student的带参的构造方法 调用Student的带参的构造方法 人数: 2 姓名: 张三 密码: null 人数: 2 姓名: 王五 密码: null */ }
读取序列化文件的类,导致重新加载Student的Class文件,静态变量恢复成默认值了.
package io; import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class TestStaticSerialable { public static void main(String[] args) { try { FileInputStream fis = new FileInputStream("test.obj"); ObjectInputStream ois = new ObjectInputStream(fis); Student1 s3 = (Student1) ois.readObject(); Student1 s4 = (Student1) ois.readObject(); //人数: 0 姓名: 王五 密码: null //这里人数0,表示静态变量没有序列化 System.out.println(s3); System.out.println(s4); ois.close(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e1) { e1.printStackTrace(); } } /** * 输出: 人数: 0 姓名: 张三 密码: null 人数: 0 姓名: 王五 密码: null */ }
赞 赏
微信赞赏 支付宝赞赏
本文固定链接: https://www.jack-yin.com/coding/thinking-in-java/2105.html | 边城网事
【下一篇】第 18 章 – java IO系统 – 序列化与反序列化 Externalizable