序列化的控制主要有三种方式:
- 实现Externalizable接口;
- 实现Serializable接口 + transient修饰符;
- 实现Externalizable接口的替代方案:实现Serializable + 添加方法;
1、实现Externalizable接口:
对于一个Externalizable对象而言,在序列化和反序列化中需要调用默认的构造函数,所以需要注意默认构造函数的访问控制符是否得当!
import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
public class Blip3 implements Externalizable {
private int i;
private String s; // No initialization
public Blip3() {
System.out.println("Blip3 Constructor");
// s, i not initialized
}
public Blip3(String x, int a) {
System.out.println("Blip3(String x, int a)");
s = x;
i = a;
// s & i initialized only in non-default constructor.
}
public String toString() {
return s + i;
}
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Blip3.writeExternal");
// You must do this:
out.writeObject(s);
out.writeInt(i);
}
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
System.out.println("Blip3.readExternal");
// You must do this:
s = (String) in.readObject();
i = in.readInt();
}
public static void main(String[] args) throws IOException,
ClassNotFoundException {
System.out.println("Constructing objects:");
Blip3 b3 = new Blip3("A String ", 47);
System.out.println(b3);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
"Blip3.out"));
System.out.println("Saving object:");
o.writeObject(b3);
o.close();
// Now get it back:
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"Blip3.out"));
System.out.println("Recovering b3:");
b3 = (Blip3) in.readObject();
System.out.println(b3);
}
}
简要说明:
- 默认构造函数Blip3()的访问控制符需要是public,而Blip3(String x, int a)的访问级别则不受限制;
- 在writeExternal和readExternal中需要显式的进行序列和反序列化;
- 如果从一个类继承于一个Externalizable对象,通常需要在writeExternal和readExternal调用父类中对应的方法;
- 代码中的资源关闭是不安全的;
2、实现Serializable接口 + transient修饰符:
transient关键字会关闭被修饰字段的序列化,从而达到对某些字段进行控制的要求!
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;
import java.util.concurrent.TimeUnit;
public class Logon implements Serializable {
private static final long serialVersionUID = 1805708074792316054L;
private Date date = new Date();
private String username;
private transient String password;
public Logon(String name, String pwd) {
username = name;
password = pwd;
}
public String toString() {
return "logon info: \n username: " + username + "\n date: " + date
+ "\n password: " + password;
}
public static void main(String[] args) throws Exception {
Logon a = new Logon("Hulk", "myLittlePony");
System.out.println("logon a = " + a);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(
"Logon.out"));
o.writeObject(a);
o.close();
TimeUnit.SECONDS.sleep(1); // Delay
// Now get them back:
ObjectInputStream in = new ObjectInputStream(new FileInputStream(
"Logon.out"));
System.out.println("Recovering object at " + new Date());
a = (Logon) in.readObject();
System.out.println("logon a = " + a);
}
}
简要说明:
- 代码中的资源关闭是不安全的;
3、实现Externalizable接口的替代方案:实现Serializable + 添加方法:
实现Serializable接口,并添加(不是“覆盖”或者“实现”)以下函数:
- private void writeObject(ObjectOutputStream stream) throws IOException;
- private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException;
这样做以后,对象的序列化和反序列化会自动的分别调用这两个方法!
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SerialCtl implements Serializable {
private static final long serialVersionUID = -760562456622756361L;
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("After:\n" + sc2);
}
}
简要说明:
- 在writeObject函数内,可以调用defaultWriteObject来执行默认的writeObject函数;
- 在readObject函数内,可以调用defaultReadObject来执行默认的readObject函数;
- 上述代码中有一些晦涩难懂的内容,需要查找一些辅助资料来理解;
4、最近在看 《Thinking in Java》, 本文整理自《Thinking in Java》,略有改动!:)