我们知道将字段设置为transient,可以避免该自动被序列化,但若反序列化时又希望该transient有值怎么办呢?
一种不使用transient的办法是使用Externalizable接口。Serializable接口默认序列化所有字段,而Externalizable接口继承自Serializable,要求实现两个方法readExternal(ObjectInput),writeExternal(ObjectOutput),默认不序列化任何字段,字段需要显式序列化。
显然transient只能和Serializable接口共用,在Serializable类中反序列化时恢复transient的值。可以通过在类中添加
private void readObject(ObjectInputStream ois);
private void writeObject(ObjectOutputStream oos);
两个方法。注:方法必须为private,此方法也非Serializable接口中的方法,但在序列化和反序列化时会自动被调用(很特殊吧)。
完整例子如下
public class TestSerializable {
public static void main(String[] args) {
String url = "jdbc:oracle:thin:@10.141.245.123:1521:FDU";
Properties prop = new Properties();
prop.setProperty("user", "system");
prop.setProperty("password", "fducs");
SerialObject serialObj = new SerialObject(url,prop);
try {
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(new java.io.File("SerialObject.out")));
oos.writeObject(serialObj);
} catch (IOException ex) {
Logger.getLogger(TestSerializable.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("SerialObject original:\n"+ serialObj);
SerialObject backObj = null;
try {
ObjectInputStream ois = new ObjectInputStream(new FileInputStream(new java.io.File("SerialObject.out")));
backObj = (SerialObject) ois.readObject();
} catch (ClassNotFoundException ex) {
Logger.getLogger(TestSerializable.class.getName()).log(Level.SEVERE, null, ex);
} catch (IOException ex) {
Logger.getLogger(TestSerializable.class.getName()).log(Level.SEVERE, null, ex);
}
System.out.println("SerialObject target:\n"+ backObj);
}
}
class SerialObject implements java.io.Serializable {
private String url;
private Properties prop;
private transient Connection con;
public SerialObject(String url, Properties prop) {
this.url = url;
this.prop = prop;
con = getConnection(url, prop);
}
private Connection getConnection(String url, Properties prop) {
Connection connect = null;
try {
Class.forName("oracle.jdbc.driver.OracleDriver");
connect = DriverManager.getConnection(url, prop);
} catch (SQLException ex) {
Logger.getLogger(TestSerializable.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(TestSerializable.class.getName()).log(Level.SEVERE, null, ex);
}
return connect;
}
@Override
public String toString(){
StringBuffer sbuf = new StringBuffer();
sbuf.append("URL="+url);
sbuf.append("\n");
sbuf.append("Properties="+prop);
sbuf.append("\n");
sbuf.append("Connection="+con);
return sbuf.toString();
}
private void readObject(ObjectInputStream ois){
try {
ois.defaultReadObject();
System.out.println("url="+url);
System.out.println("prop="+prop);
con = getConnection(url,prop);
} catch (IOException ex) {
Logger.getLogger(SerialObject.class.getName()).log(Level.SEVERE, null, ex);
} catch (ClassNotFoundException ex) {
Logger.getLogger(SerialObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
private void writeObject(ObjectOutputStream oos){
try {
oos.defaultWriteObject();
} catch (IOException ex) {
Logger.getLogger(SerialObject.class.getName()).log(Level.SEVERE, null, ex);
}
}
}