[英]Java Inheritance: Difference while inheriting super class members and variables
我正在經歷Java繼承,並嘗試了以下代碼
class A {
public int x = 1;
public void print1() {
System.out.println("Print from A");
}
}
class B extends A {
public int x = 2;
public void print1() {
System.out.println("Print from B");
}
}
class C extends B {
public int x = 3;
public void print1() {
System.out.println("Print from C");
}
public static void main(String aa[]) {
C c = new C();
((A) c).print1();
System.out.println(c.x);
System.out.println(((A) c).x);
}
}
輸出是
從C打印
3
1個
現在,我的問題是我可以從class C instance c
訪問class A member x
,但是為什么我不能訪問class A method print1()
。 我知道,如果我願意,我可以叫new A().print1();
。 但是,我想直接從C類的實例訪問它。 因此,通過覆蓋方法,頂部的父類方法是否在底部的子類中丟失了? 但是,父類成員將保留(盡管隱藏)。 為什么這樣? 有沒有一種方法可以在不創建A
實例的情況下從C
類中的A
類調用方法?
編輯
當你說((A)c).print1();
,JVM知道實際需要調用的實例是print1()
,其類型為C
因此將執行類C
的print1()
版本。
但是當您鍵入[ ((A)c).x
,您是在指狀態,而不是行為,也是在使用類型A
引用。 因為編譯器知道什么是類型引用(在本例中為A
),所以在編譯時確定將使用x
哪個版本。 這就是為什么您看到A
的狀態。
Java doc中的以下語句可能對您也很有趣:
在類中,即使其類型不同,與超類中的字段具有相同名稱的字段也會隱藏超類的字段。 在子類中,無法通過其簡單名稱引用超類中的字段。 相反,必須通過super訪問該字段,這將在下一部分中介紹。 一般來說,我們不建議隱藏字段,因為這會使代碼難以閱讀。
回答您的問題:
問題1:
我的問題是我能夠從C類實例c訪問A類成員x
關於變量x
,因為它被聲明為public
,所以不能對其應用任何業務驗證。 而且,將其聲明為public
的開發人員知道,封裝的概念現在不能應用(顯然不建議這樣做)。 因此,允許使用子實例訪問父狀態不會有任何危害。 因此,通過使用[ ((A)c).x
,您可以從類A
訪問x
。
問題2:
但是,父類成員將保留(盡管隱藏)。 為什么這樣?
這是因為Java不允許您隨意使用super.super.super..
來訪問繼承層次結構中任何父級的行為。 其背后的原因是保留封裝。 您只能使用super
關鍵字訪問直接父類的行為,但不能超過此行為。
為了進一步解釋,假設您具有B
類的實現:
class B extends A {
public int x = 2;
public void print1() {
if(x >= 2) {
System.out.println("Print from B");
}
}
}
現在,如果允許使用super.super
,則可以輕松地在類B
print1()
方法中繞過驗證,並可以從類C
的實例調用A
的print1()方法。
問題3:
但是,父類成員將保留(盡管隱藏)。 為什么這樣?
如前所述,保留封裝。
問題4:
有沒有一種方法可以在不創建A實例的情況下從C類中的A類調用方法?
因此,無法使用C
的實例從A
訪問print1()
。
當您覆蓋已經在base(parent)類中實現的函數時,在子類中調用該函數時,子類中的類將自動調用,因此在您情況下,當您調用C對象的print1()
時:
C c = new C();
c.print1();
您將調用覆蓋功能。 但是,如果在程序的任何部分中您覺得在任何情況下都需要調用頂級父類( super
無法實現),則應重新考慮您的設計策略; 也許您不應該覆蓋print1()
,甚至不應該將print1()
首先放在基類中
在面向對象的編程中,只有方法才具有被覆蓋的能力。 您不能覆蓋數據成員。 這解釋了為什么獲得輸出。
A
print1()
方法在C
被覆蓋,並且c
是C
的對象。 因此,它將調用C
的print1()
方法。 另一方面,變量x
不被覆蓋。
要調用超類方法,您可以執行以下操作:
super.print1();
在這里,所有類都使用了同名實例變量來混淆編譯器,但是您應該知道,只有成員函數才能被覆蓋,而成員變量不能被覆蓋。
因此,所有三個x
將分別存儲在內存中。 但是public void print1()
將被其子類覆蓋。 所以,
((A)c).print1();
這段代碼將調用C類中定義的重寫方法。無論在哪個類中強制轉換C
類的Object都無關緊要。 但是在第二種情況下((A)c).x
將打印A
類的值。
((A)c).x
:-這將引用變量x
屬於Class A
而不是Class C
因為變量從未在繼承中被覆蓋。 ((A)c).print1(); 實際上,它類似於c.print1();。 。 不管您使用Class A進行類型轉換,它仍將調用Class C的print1()函數。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.