本文来自:高爽|Coder,原文地址:http://blog.csdn.net/ghsau/article/details/19120019,转载请注明。
上文中实现了序列化和逆序列化一个简单的Name对象,下面来看一个稍复杂的情况,Name类中复合了其它类。
Name.java:
import java.io.Serializable; /** * 可序列化的类,需要实现Serializable接口 * @author 爽 * */ public class Name implements Serializable { private static final long serialVersionUID = 1L; private String firstname; private String lastname; private Nickname nickname; public Name() {} public Name(String firstname, String lastname) { this.firstname = firstname; this.lastname = lastname; } public Name(String firstname, String lastname, Nickname nickname) { this.firstname = firstname; this.lastname = lastname; this.nickname = nickname; } public String getFirstname() { return firstname; } public void setFirstname(String firstname) { this.firstname = firstname; } public String getLastname() { return lastname; } public void setLastname(String lastname) { this.lastname = lastname; } public Nickname getNickname() { return nickname; } public void setNickname(Nickname nickname) { this.nickname = nickname; } @Override public String toString() { return "我的名字是" + firstname + "," + lastname + "\n我的昵称是" + nickname; } }Nickname.java:
import java.io.Serializable; /** * 昵称类 * @author 爽 * */ public class Nickname implements Serializable { private static final long serialVersionUID = 1L; private String name; public Nickname() {} public Nickname(String name) { this.name = name; } public String getName() { return name; } public void setName(String name) { this.name = name; } @Override public String toString() { return name; } }WriteObject.java:
import java.io.IOException; import com.runqianapp.test.bean.Name; import com.runqianapp.test.bean.Nickname; public class WriteObject { public static void main(String[] args) throws IOException { Nickname nickname = new Nickname("黑曼巴"); Name name = new Name("科比", "布莱恩特", nickname); Serializations.serialize(args[0], name); } }运行后,指定目录下会生成相应文件,再次运行ReadObject.java,会得到如下输出信息:
我的名字是科比,布莱恩特 我的昵称是黑曼巴在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。在序列化过程中,可能会遇到不支持可序列化接口的对象,在此情况下,将抛出 NotSerializableException,并将标识不可序列化对象的类。如将Nickname.java去掉Serializable接口,再次运行WriteObject.java,会抛出如下异常:
Exception in thread "main" java.io.NotSerializableException: Nickname at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1180) at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1528) at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1493) at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1416) at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1174) at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:346) at Serializations.serialize(Serializations.java:26) at WriteObject.main(WriteObject.java:13)
我们可以用transient来修饰nickname属性,这样该类就可以正常序列化了,但是nickname中的属性也就无法序列化了,那我们如何让不能序列化的类NickName中的name属性可以序列化和反序列化呢?在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:
private void writeObject(java.io.ObjectOutputStream out) throws IOException; private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException;在对象序列化时,会调用writeObject方法,在对象反序列化时,会调用readObject方法。writeObject 方法负责写入特定类的对象的状态,以便相应的 readObject 方法可以还原它。通过调用 out.defaultWriteObject 可以调用保存 Object 的字段的默认机制。readObject 方法负责从流中读取并还原类字段。它可以调用 in.defaultReadObject 来调用默认机制,以还原对象的非静态和非瞬态字段。所以,我们可以在Name类中加入如下方法:
private void writeObject(java.io.ObjectOutputStream out) throws IOException { // 默认序列化机制 out.defaultWriteObject(); // 序列化nickname中的name属性 out.writeObject(nickname.getName()); } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { // 默认逆序列化机制 in.defaultReadObject(); // 逆序列化一个nickname对象 nickname = new Nickname(in.readObject().toString()); }这样就可以处理其不可序列化的复合类Nickname中的name属性序列化及反序列化。运行WriteObject和ReadObject,序列化和反序列化成功。这两个方法如何实现取决于最终的需求,上面的例子是我想的一个比较符合应用场景的实例。