反序列化时回复transient字段

反序列化时恢复transient字段
我们知道将字段设置为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);
        }
    }
}