簡體   English   中英

當在子類的初始化塊中重新初始化時,實例變量被覆蓋,就像實例方法一樣,它不應該被覆蓋

[英]Instance variable, when re-initialised in sub class' initialization block, is overridden like instance method, which it should not

我剛開始學習Java。我明白了

  1. 與實例方法不同,實例變量不能被覆蓋,並且在多態訪問時,JVM在運行時不會動態選擇它。
  2. 執行流程:靜態塊,超級構造函數,初始化塊,然后是構造函數。

但是我被困在一個代碼中,在那里我多態地調用了一個實例變量,但它顯示了重寫的值(它不應該顯示)。 在子類的init塊中重寫實例變量。

package package1;

public class Other {

    public static void main(String [] args){
            Parent referToChild = new Child();
            Parent referToChildTwo = new ChildTwo();
            System.out.println("age as referred by referToChild reference variable is:" + referToChild.age);// prints 35 (doubt 1)
            System.out.println("age as referred by referToChildTwo reference variable is:" + referToChildTwo.age);// prints 50 (doubt 2)
            System.out.println("money as referred by Other reference variable is:" + referToChild.money);
            //System.out.println("Other reference variable is:" + othObj.age);
    }
}

class Child extends Parent{
    // init block 
    {
        age = 35;
    }
}

class ChildTwo extends Parent{
    public int age;
    {
        age = 40;
    }
}

class Parent{
     public int age = 50;
     public int money = 100;
}

我得到的答案是:

35

50

100

所以我的懷疑是:

懷疑1:為什么它顯示“35”,它應該顯示超類'變量的值50。

懷疑2:當它顯示最后一個案例的子類'變量值時,為什么不為這種情況。

為什么它顯示“35”,它應該顯示超類'變量的值為50。

Parent類中初始化變量age 之后 ,子類Child的初始化塊執行。 因此, age首先初始化為50 ,然后是35

關於創建新類實例的Java語言規范第12.5節詳細解釋了這一點,相關部分用粗體表示:

在作為結果返回對新創建的對象的引用之前,處理指示的構造函數以使用以下過程初始化新對象:

  1. 將構造函數的參數分配給此構造函數調用的新創建的參數變量。

  2. 如果此構造函數以同一個類中的另一個構造函數的顯式構造函數調用(第8.8.7.1節)開頭(使用this ),則使用這五個相同步驟計算參數並以遞歸方式處理該構造函數調用。 如果該構造函數調用突然完成,則此過程突然完成,原因相同; 否則,繼續步驟5。

  3. 此構造函數不以同一個類中的另一個構造函數的顯式構造函數調用開頭(使用this )。 如果此構造函數用於Object以外的類,則此構造函數將以超類構造函數的顯式或隱式調用開始(使用super )。 使用這五個相同的步驟評估參數並遞歸處理超類構造函數調用 如果該構造函數調用突然完成,則此過程突然完成,原因相同。 否則,繼續執行步驟4。

  4. 為此類執行實例初始值設定項和實例變量初始值設定 ,將實例變量初始值設定項的值按從左到右的順序分配給相應的實例變量,在這些順序中,它們以文本方式出現在類的源代碼中。 如果執行任何這些初始值設定項導致異常,則不會處理其他初始化程序,並且此過程會突然完成同樣的異常。 否則,繼續步驟5。

  5. 執行此構造函數的其余部分。 如果執行突然完成,則此過程突然完成,原因相同。 否則,此過程正常完成。

至於第二個問題, referToChildTwo被聲明為Parent類型,而它的實際類型是ChildTwo ChildTwo實例有兩個age字段,一個在ChildTwo定義,另一個從Parent繼承。

當您編寫表達式referToChildTwo.age ,將評估在Parent繼承的字段。 要評估子類中定義的那個,您需要轉換變量,即((ChildTwo)referToChildTwo).age

它不能被覆蓋,但它由子類繼承,只要它在父類中不是私有的。 他們可以訪問它,包括讀取和寫入它。

重寫是創建一個新成員,它是當前類的一部分,它具有與父類成員相同的定義,並且當您以多態方式使用該對象時,將訪問該成員。

例如:

class Parent {
   public int age = 50;
}

class Child {
   public int age = 80;
}

在這里,我們定義了一個新成員, age ,它與父母的age分開。 如果您使用this.ageChild內部訪問它,您將獲得80 如果您使用super.age訪問父母的age ,您將獲得50

但這並不是最重要的,因為如果您以多態方式使用該對象,它將訪問父級的age

Child childObj = new Child();
Parent parentObj = childObj;

System.out.println( childObj.age ); // Will print 80
System.out.println( parentObj.age ); // Will print 50

盡管事實上它們都是同一個對象。 那是因為孩子隱藏了字段而不是覆蓋它。

簡單地在從父項繼承的字段中指定值不會覆蓋。 這是繼承的一部分。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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