2017年11月12日 星期日

Serialization 序列化

用途:當想要儲存一個或多個object state(instance variable)的時候,就需要使用序列化;若沒有的話,實作就要特別小心傳送過去的值和收到的值有對應成功,非常麻煩。
- 除了被標示為transient的variable不會儲存外,其他都會被儲存
- 必須藉由implements Serializable interface來明確選擇哪些object可以被serialize
- implements Serializable不需要override任何methods
- 若有沒辦法implements Serializable interface(比如class設定成final無法修改)的情況下且需要儲存狀態,需要自行實作writeObject()或 readObject(),例:

class Dog implements Serializable {
 transient private Collar theCollar; // 不能序列化它 private int dogSize,自行實作
 public Dog(Collar collar, int size) {
  theCollar = collar;
  dogSize = size;
 }
 public Collar getCollar() {
  return theCollar;
 }
 private void writeObject(ObjectOutputStream os) { // override
  // throws IOException {
  try {
   os.defaultWriteObject();
   os.writeInt(theCollar.getCollarSize()); // 自行包裝dog size
  } catch (Exception e) {
   e.printStackTrace();
  }
 }
 private void readObject(ObjectInputStream is) { // override

  // throws IOException, ClassNotFoundException { try {
  is.defaultReadObject();
  theCollar = new Collar(is.readInt());// 自行取出dog size
 } catch (Exception e) {
  e.printStackTrace();
 }
}
}

- 若superclass implements Serializable,則所有底下的subclass都會跟著繼承,也就是subclass不需要明確的標示Serializable也能夠存取state
- 若superclass沒有implements Serializable,任何維護在superclass的state(從superclass繼承下來,且沒有override的),都不會回覆,將被重新初始化(就像是跑了一次 superclass的constructor)
- 若使用transient標示變數,代表不需要序列化此值,且該值會被恢復成default值,例:

class TestSer{
    public static void main(String[] args){
        SpecialSerial s = new SpecialSerial();
        try{
            ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("myFile"));
            os.writeObject(s); //s1.y ==7, s1.z == 9
            os.close();
            ObjectInputStream is = new ObjectInputStream(new FileInputStream("myFile"));
            SpecialSerial s2 = (SpecialSerial)is.readObject();
            is.close();
            System.out.println(s2.y + " " + s2.z); // s2.y == 0, s2.z == 10
        }catch (Exception e){
            System.out.println("exc");
        }
    }
}
class SpecialSerial implements Serializable{
    transient int y = 7;
    static int z = 9;
}

注意:

  1. 最後output s2.y=0,原因是被標示為transient,不管initial值為何,都會變成該形態的default值
  2. 因為此例中z是static,代表memory只有存一份記憶體,且和instance無關,是class等級。所以最後取出的時候,值也會跟著變成10。
  • 綜合以上兩點代表static&transient 變數所屬的object並不能夠被序列化。




沒有留言:

張貼留言