[英]For a Serializable super class, if we serialize the subclass, why does the super constructor is invoked
import java.io.*;
class Animal implements Serializable
{
String type;
Animal()
{
System.out.println("Animal's default constructor");
}
}
class Dog extends Animal
{
int weight;
Dog(String type, int weight)
{
this.type = type;
this.weight = weight;
System.out.println("running the Dog's dual arg'd constructor");
}
}
class DogSerialized
{
public static void main(String[] args)
{
Dog d = new Dog("hairy",29);
System.out.println(d.type+" "+d.weight);
try{
FileOutputStream fs = new FileOutputStream("fileSerialized.ser");
ObjectOutputStream os = new ObjectOutputStream(fs);
os.writeObject(d);
os.close();
}//end of try block
catch(Exception e){}
Dog d1 = null;
try{
FileInputStream fis = new FileInputStream("fileSerialized.ser");
ObjectInputStream ois = new ObjectInputStream(fis);
d1 = (Dog) ois.readObject();
}//end of try block
catch(Exception e){}
System.out.println(d1.type+" "+d1.weight);
}
}
運行此代碼,我可以看到調用了super的構造函數。 我不知道為什么/如何調用它。 您能解釋一下這種特殊情況嗎(對超級可序列化的子類實例進行序列化/反序列化)
它的代碼Dog d = new Dog("hairy",29);
那就是在調用超類構造函數而不是序列化過程。 每當您創建子類的對象時,它都會調用其父類的構造函數。
您的問題與序列化無關。 使用new
創建任何實例后,構造函數就會運行。 當對象反序列化時,它們不會運行。
超類的構造函數被隱式調用,因為編譯器將對super();
插入一個無參數的調用super();
對您而言,作為子類的構造函數中的第一條語句。 為了更清楚地理解這個概念,您必須了解構造函數鏈接 。 沒什么,但是,在Java中,每個構造函數都通過對super();
的隱式調用來調用其超類的構造函數super();
除非您調用this();
明確地(指重載的建設者)。
在您的情況下, Dog extends Animal
而Animal extends Object
(因為我們在Java中創建的每個類都將擴展Object
類)。
現在,當您說Dog d = new Dog("hairy",29);
在您的主要方法中,將執行以下步驟
Dog
構造函數被調用。 但是它還不會初始化變量的type
和weight
。 由於Dog的構造函數中的第一條語句是super();
(隱式),將調用Animal
類的構造函數。
同樣,Animal的構造函數中的第一條語句是super();
(隱式),因此將調用Object
類的構造函數。
此時,我們處於堆棧的頂部,因為Java中的Object
類在繼承層次結構中處於最高級別。 這樣,Object構造函數完成並彈出堆棧。
Animal
。 在super()之后,它將完成其中的語句; 語句並彈出堆棧。 Dog
。 它還將完成其中所有剩余的語句並彈出堆棧。 以您的示例為例,當您調用Dog d = new Dog("hairy",29);
編譯器插入super();
如下所示
Dog(String type, int weight)
{
super(); //You can also explicitly state this. This will invoke Animal() constructor before going to below statements.
this.type = type;
this.weight = weight;
System.out.println("running the Dog's dual arg'd constructor");
}
要點:
super();
的隱式調用super();
或顯式調用this();
當您顯式調用super();
其中的參數應與超類構造函數的參數匹配。 例如,如果您的Animal構造函數具有2個類似Animal(String type, int weight)
,則您調用super();
在您的Dog構造函數中,您會得到編譯器錯誤。
構造函數永遠不會被繼承。 它們不能被覆蓋。
構造函數在子類中沒有繼承。 因此,為了創建子類對象,首先需要通過調用super構造函數來創建基礎(超類)對象(在您的示例中非常正常)。 創建super之后,將調用子類構造函數以添加任何子類字段。 對象就像陰離子:內層是超類,外層是子類。
您可以在本文中閱讀有關它的更多信息。
接口(是否可序列化)對調用構造函數沒有任何影響。
子類在創建時始終調用其父級的構造函數。
您可以嘗試將Animal類更改為:
class Animal implements Serializable
{
String type;
Animal(String something)
{
System.out.println("Animal's default constructor");
}
}
該代碼將無法編譯,因為在Dog構造函數中,您不會調用其父級的構造函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.