亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

Java多態 - 如何確定是否會調用超類與子類方法以及超類變量與子類變量?

Java多態 - 如何確定是否會調用超類與子類方法以及超類變量與子類變量?

catspeake 2021-11-17 16:59:40
示例代碼:public class A {    public int number;    public A(int number) {        this.number = number;    }    public int getNumber() {        return number;    }}public class B extends A{    public int number;    public B(int number) {        super(number);    }    public int getNumber() {        return number;    }}public class C {    public static void main(String args[]) {        A test1 = new B(2);        B test2 = new B(2);        System.out.println(test1.number) // prints 2        System.out.println(test2.number) // prints 0        System.out.println(test1.getNumber()) //prints 0        System.out.println(test2.getNumber()) // prints 0    }}如上所示,test1.number 不等于 test1.getNumber()。因此,當我使 test1 成為 A 類型的對象時, test1.number 指的是 A 類中的 int 數。但是當我調用 test1.getNumber() 時,它是在 B 類中調用 getNumber() 嗎?為什么會這樣?
查看完整描述

3 回答

?
慕俠2389804

TA貢獻1719條經驗 獲得超6個贊

Java 中的所有方法都是虛擬的。我馬上就會明白這意味著什么。

所以,在這一行:

A test1 = new B(2);

您已將類的新實例分配給B聲明為包含A.

當您使用 時test1.number,您使用的是number在 class 中聲明的變量A,假設B調用的構造函數super(number)將為 2。

但是,當您調用 時test1.getNumber(),這就是 virtual 發揮作用的地方。Virtual 意味著它將始終調用構造類中的方法,而不是您將其聲明為的變量類型。換句話說,不是像你想象AgetNumber那樣調用's ,它實際上調用的是B's getNumber。 B的構造函數沒有為Bnumber變量賦值,所以你得到 0。


查看完整回答
反對 回復 2021-11-17
?
長風秋雁

TA貢獻1757條經驗 獲得超7個贊

我根據這個網站找到了一些解釋 Java 類層次結構的信息。當您擴展一個類時,您基本上是從該類復制代碼并將其放入擴展它的代碼中,這樣您就不必重寫方法,而是在類 B 中進行。因此,不要在類中使用該方法A 類它將使用您編碼到 B 類中的那個。

https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html


查看完整回答
反對 回復 2021-11-17
?
慕斯王

TA貢獻1864條經驗 獲得超2個贊

那是因為 Java 允許覆蓋方法,但不允許覆蓋字段。

規范寫道

如果一個類聲明了一個具有特定名稱的字段,那么該字段的聲明被稱為隱藏了超類和類的超接口中具有相同名稱的字段的任何和所有可訪問聲明。

在這方面,字段隱藏不同于方法隱藏(第 8.4.8.3 節),因為在字段隱藏中沒有區分靜態和非靜態字段,而在方法隱藏中區分靜態和非靜態方法.

如果隱藏字段是靜態的,則可以使用限定名稱(第 6.5.6.2 節)訪問隱藏字段,或者使用包含關鍵字 super(第 15.11.2 節)或轉換為超類類型的字段訪問表達式。

在這方面,字段的隱藏類似于方法的隱藏。

也就是說,每個實例B都有兩個不同的字段,它們碰巧共享相同的名稱。當您在諸如 的字段訪問表達式中使用字段名稱時test1.number,將根據 的編譯時類型解釋該字段名稱test1。

相反,實例方法可以被覆蓋

在類 C 中聲明(或由其繼承)的實例方法 mC 從 C 中覆蓋在類 A 中聲明的另一個方法 mA,如果以下所有條件都為真:

  • C 是 A 的子類。

  • ...

  • mC 的簽名是 mA 簽名的子簽名(第 8.4.2 節)。

(其中“子簽名”表示方法名稱和參數兼容。)

覆蓋解決如下

否則,將調用實例方法并存在目標引用。如果目標引用為空,則此時拋出 NullPointerException。否則,目標引用被稱為指向目標對象,并將用作調用方法中關鍵字 this 的值。

...

否則,可能會發生 [...] 覆蓋。使用動態方法查找。動態查找過程從一個類 S 開始,確定如下:

  • 如果調用模式是接口或虛擬,則 S 最初是目標對象的實際運行時類 R。

  • ...

動態方法查找使用以下過程來搜索類 S,然后根據需要搜索類 S 的超類和超接口以查找方法 m。

也就是說,如果您編寫test1.getNumber(),運行時將評估test1以獲取目標對象,確定其類,然后在該類中尋找合適的方法。

在您的示例中,test1引用了 class 的對象B,這B.getNumber()就是調用的原因。

B.getNumber()then的實現繼續 read B.number,它從未被分配過,因此仍然包含它的默認值 0。


查看完整回答
反對 回復 2021-11-17
  • 3 回答
  • 0 關注
  • 233 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號