簡體   English   中英

對於Serializable超類,如果我們對子類進行序列化,為什么調用super構造函數

[英]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 AnimalAnimal extends Object (因為我們在Java中創建的每個類都將擴展Object類)。

現在,當您說Dog d = new Dog("hairy",29); 在您的主要方法中,將執行以下步驟

  1. 首先,您的Dog構造函數被調用。 但是它還不會初始化變量的typeweight
  2. 由於Dog的構造函數中的第一條語句是super(); (隱式),將調用Animal類的構造函數。

  3. 同樣,Animal的構造函數中的第一條語句是super(); (隱式),因此將調用Object類的構造函數。

  4. 此時,我們處於堆棧的頂部,因為Java中的Object類在繼承層次結構中處於最高級別。 這樣,Object構造函數完成並彈出堆棧。

  5. 堆棧中的下一個構造函數是Animal 在super()之后,它將完成其中的語句; 語句並彈出堆棧。
  6. 堆棧中的最終構造函數是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");
    }

要點:

  1. 任何構造函數中的第一條語句都是對super();的隱式調用super(); 或顯式調用this();
  2. 當您顯式調用super(); 其中的參數應與超類構造函數的參數匹配。 例如,如果您的Animal構造函數具有2個類似Animal(String type, int weight) ,則您調用super(); 在您的Dog構造函數中,您會得到編譯器錯誤。

  3. 構造函數永遠不會被繼承。 它們不能被覆蓋。

構造函數在子類中沒有繼承。 因此,為了創建子類​​對象,首先需要通過調用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM