Java中的繼承與物件序列化


在序列化中,當引入繼承時,根據超類和子類,定義了某些情況,這使得對每種情況下序列化的理解更加簡單。應該遵循的基本規則如下所示。

1. 超類實現了Serializable介面,而子類沒有。

在這種情況下,即使子類沒有實現Serializable介面,子類的物件也會在超類序列化時預設被序列化。

示例

public class TestSerialization {
   public static void main(String[] args) throws IOException, ClassNotFoundException {
      B obj = new B();
      FileOutputStream fos = new FileOutputStream("abc.ser");
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(obj);
      FileInputStream fis = new FileInputStream("abc.ser");
      ObjectInputStream ois = new ObjectInputStream(fis);
      B obj1 = (B)ois.readObject();
      System.out.println(obj1.i + " " + obj1.j);
   }
}
class A implements Serializable {
   int i = 10;
}
class B extends A {
   int j =20;
}

輸出

value of i is : 10 & value of j is : 20

2. 超類沒有實現Serializable介面,而子類實現了。

在這種情況下,繼承自子類的超類例項變數不會被序列化,並且在子類序列化期間會丟失其分配的值。此外,JVM在子類序列化期間會將預設初始化值重新分配給這些超類的例項變數。在此場景中需要注意的另一點是,超類必須具有預設的無引數建構函式,因為JVM在反序列化期間會訪問超類。如果此建構函式不存在,則會遇到編譯時異常。

示例

public class TestSerialization {
   public static void main(String[] args) throws IOException,ClassNotFoundException {
      B obj = new B(10,20);
      FileOutputStream fos = new FileOutputStream("abcd.ser");
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(obj);
      FileInputStream fis = new FileInputStream("abcd.ser");
      ObjectInputStream ois = new ObjectInputStream(fis);
      B obj1 = (B) ois.readObject();
      System.out.println("value of i is : " +obj1.i + " & value of j is : " + obj1.j);
   }
}
class A {
   int i;
   A() {
      System.out.println("default constructor called of parent class.");
   }
   A(int i) {
      this.i=i;
   }
}
class B extends A implements Serializable {
   int j;
   B(int i , int j) {
      super(i);
      this.j=j;
   }
}

輸出1

存在預設建構函式時。

default constructor called of parent class.
value of i is : 0 & value of j is : 20

輸出2

不存在預設建構函式時。

Exception in thread "main" java.io.InvalidClassException: B; B; no valid constructor

3. 需要序列化超類但不序列化子類(自定義序列化)。

為了防止子類被序列化,我們需要實現writeObject()和readObject()方法,這些方法在序列化和反序列化期間由JVM執行,並且需要從這些方法中丟擲NotSerializableException異常。我們也可以在這些方法中提供自定義邏輯,這些邏輯將在序列化/反序列化期間執行。

示例

public class TestSerialization {
   public static void main(String[] args) throws IOException, ClassNotFoundException {
      B obj = new B();
      FileOutputStream fos = new FileOutputStream("abc.ser");
      ObjectOutputStream oos = new ObjectOutputStream(fos);
      oos.writeObject(obj);
      FileInputStream fis = new FileInputStream("abc.ser");
      ObjectInputStream ois = new ObjectInputStream(fis);
      B obj1 = (B)ois.readObject();
      System.out.println("value of i is : " + obj1.i + " & value of j is : " + obj1.j);
   }
}
class A implements Serializable {
   int i = 10;
}
class B extends A {
   int j =20;
}
// implementing writeObject method,
private void writeObject(ObjectOutputStream out) throws IOException {
   throw new NotSerializableException();
}
// implementing readObject method,
private void readObject(ObjectInputStream in) throws IOException {
   throw new NotSerializableException();
}

輸出

Exception in thread "main" java.io.NotSerializableException
at B.writeObject(A.java:20)

更新於:2020年6月25日

2K+ 瀏覽量

啟動您的職業生涯

完成課程獲得認證

開始學習
廣告
© . All rights reserved.