前篇介绍了标识了transient与static的变量是不被序列化的,以下介绍更为灵活控制对象序列化和反序列化的方法,甚至可以控制序列化非本类的数据。
一、接口介绍
当对象继承了java.io.Externalizable接口时,可以更灵活得控制整个序列化与反序列化的过程。以下是java.io.Externalizable接口的关系图:
从上图中可以看出,java.io.Externalizable接口继承了java.io.Serializable接口,以此可知实现了java.io.Externalizable接口后,类可以被序列化和反序列化。
java.io.Externalizable源代码 |
public interface Externalizable extends java.io.Serializable { /** * The object implements the writeExternal method to save its contents * by calling the methods of DataOutput for its primitive values or * calling the writeObject method of ObjectOutput for objects, strings, * and arrays. * * @serialData Overriding methods should use this tag to describe * the data layout of this Externalizable object. * List the sequence of element types and, if possible, * relate the element to a public/protected field and/or * method of this Externalizable class. * * @param out the stream to write the object to * @exception IOException Includes any I/O exceptions that may occur */ void writeExternal(ObjectOutput out) throws IOException; /** * The object implements the readExternal method to restore its * contents by calling the methods of DataInput for primitive * types and readObject for objects, strings and arrays. The * readExternal method must read the values in the same sequence * and with the same types as were written by writeExternal. * * @param in the stream to read data from in order to restore the object * @exception IOException if I/O errors occur * @exception ClassNotFoundException If the class for an object being * restored cannot be found. */ void readExternal(ObjectInput in) throws IOException, ClassNotFoundException; } |
以上代码可以看出,java.io.Externalizable接口声明了两个方法writeExternal(ObjectOutput out)和readExternal(ObjectInput in)。
writeExternal(ObjectOutput out):当对象进行序列化时,此方法会被执行,该对象需要序列化哪些数据可在此方法进行实现。
readExternal(ObjectInput in):当对象进行反序列化时,此方法会被执行,需要反序列哪些字段在此方法中实现。
二、实践
实现java.io.Externalizable的类 |
public class User implements Externalizable{ private static final long serialVersionUID = 1L; private String loginName; private String password; private String name; private String sex; public User() { } public User(String loginName, String password, String name, String sex) { this.loginName = loginName; this.password = password; this.name = name; this.sex = sex; } public String getLoginName() { return loginName; } public void setLoginName(String loginName) { this.loginName = loginName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public String toString() { return "User{" + "loginName='" + loginName + '\'' + ", password='" + password + '\'' + ", name='" + name + '\'' + ", sex='" + sex + '\'' + '}'; } public void writeExternal(ObjectOutput out) throws IOException { System.out.println("开始序列化-------------------------"); out.writeObject(loginName); out.writeObject(name); out.writeObject(sex); out.writeObject(new Date());//不存在当前类也可以被序列化 } public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { System.out.println("开始反序列化------------------------"); this.loginName = (String) in.readObject(); this.name = (String)in.readObject(); this.sex = (String)in.readObject(); System.out.println(((Date)in.readObject()).toString()); } } |
序列化代码片段 |
public void externalizable(){ try { User user = new User("login.test", "123456", "test", "男"); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("User.txt")); oos.writeObject(user); oos.flush(); oos.close(); } catch (IOException e) { e.printStackTrace(); } } |
控制台结果 |
开始序列化------------------------- |
序列化后文件:
反序列化代码片段 |
public void dexternalizable(){ try { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("User.txt")); User user = (User)ois.readObject(); System.out.println(user); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } |
控制台结果 |
开始反序列化------------------------ Tue Oct 25 23:07:34 CST 2016 User{loginName='login.test', password='null', name='test', sex='男'} |
以上结果可以看出:
1、序列化时,执行了writeExternal(ObjectOutput out)方法;
2、反序列化时,执行了readExternal(ObjectInput in)方法;
3、writeExternal(ObjectOutput out)方法中序列化了当前日期,在反序列化时成功获得了日期数据。
4、password字段并没有被序列化。
注意点:
1、在序列化方法中,写入了几个字段且写入的顺序,在反序列化方法中必须按照序列化方法中的顺序及数量获取,否则有可能出现反序列化数据类型不对或sex字段的值给赋值到name字段上。
2、如以上例子,若反序列化方法中没有反序列sex字段,那么就无法取得Date数据。