3 回答

TA貢獻1719條經驗 獲得超6個贊
Java 中的所有方法都是虛擬的。我馬上就會明白這意味著什么。
所以,在這一行:
A test1 = new B(2);
您已將類的新實例分配給B
聲明為包含A
.
當您使用 時test1.number
,您使用的是number
在 class 中聲明的變量A
,假設B
調用的構造函數super(number)
將為 2。
但是,當您調用 時test1.getNumber()
,這就是 virtual 發揮作用的地方。Virtual 意味著它將始終調用構造類中的方法,而不是您將其聲明為的變量類型。換句話說,不是像你想象A
的getNumber
那樣調用's ,它實際上調用的是B
's getNumber
。 B
的構造函數沒有為B
的number
變量賦值,所以你得到 0。

TA貢獻1757條經驗 獲得超7個贊
我根據這個網站找到了一些解釋 Java 類層次結構的信息。當您擴展一個類時,您基本上是從該類復制代碼并將其放入擴展它的代碼中,這樣您就不必重寫方法,而是在類 B 中進行。因此,不要在類中使用該方法A 類它將使用您編碼到 B 類中的那個。
https://docs.oracle.com/javase/tutorial/java/IandI/subclasses.html

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。
添加回答
舉報