[英]Why can't subclass see method of parent class?
我有三節課。
A級
public class A {
}
B級
public class B extends A {
public void hello(){
System.out.println("hello");
}
}
C級
public class C extends B {
}
類測驗
public class Test {
public static void main(String[] args) {
A a = new C();
a.hello(); // The method hello() is undefined for type A
}
}
上面的代碼將無法編譯,因為它報告一個錯誤,內容為“方法A類型的hello()未定義”
我的問題是,由於“ a”是C
對象,為什么a.hello()
在B
的父類中不使用hello()
方法?
如果我向A
類添加hello方法,則只有上面的代碼才使用B類中的hello()
,但是為什么我必須向A
類中添加hello()
才能使用B
類中的方法?
A
是層次結構中的頂級類。 它僅查看其中定義的那些方法。 A
不能訪問其子類定義的方法。 當然,您可以將C
分配給變量A
,然后可以在可以使用A
任何地方使用它,但是現在C
將限於A
擁有的方法。
當您考慮它時,這是有道理的。 定義類型( A
)時,您希望它的行為符合您的定義(其中不包括有關C
字段和方法的任何內容)。 您不會期望它突然擁有子類可能定義的所有內容(例如,想象一下這樣的情況:一百個人以各種方式擴展了您的班級-頂級班級將變得難以置信地膨脹和泛濫)。
這就是子類擴展父類的原因-它們添加了未(可能不應該)在其父類中定義的其他功能。 但是,父級本身並不了解其他功能,因此無法使用它。 每個類只能使用其定義的內容或父類定義的內容。 因此,當您將C
分配給父類的類型時,只會獲得A
知道的那些方法(但使用C
的實現)。
考慮:
public class Animal {
public void walk() {
System.out.println("Walking");
}
}
public class Dog extends Animal {
public void bark() {
System.out.println("Woof");
}
@Override
public void walk() {
System.out.println("Doggy walk");
}
public static void main(String[] args) {
Dog dog = new Dog();
Animal animal = new Animal();
Animal animalDog = new Dog();
dog.walk(); // "Doggy walk"
dog.bark(); // "Woof"
animal.walk(); // "Walking"
animal.bark(); // Error: bark() is not defined in the Animal class
animalDog.walk(); // "Doggy walk"
animalDog.bark(); // Error: Animal class has no bark()
}
}
由於我們將Dog
分配為Animal
類型,因此只能使用Animal
類中定義的方法。 但是請注意,該行為將是您在Dog
類中為同一方法定義的行為。
如果必須使用該方法,並且由於某種原因尚未將其分配給具有該方法的類型,則應進行相應的強制轉換,例如:
((Dog) animalDog).bark(); // "Woof"
當將a
定義為A
類型對象( A a = new C();
)時,它只能訪問A
類型的成員和方法。 要執行所需的操作,請在類型A
上定義hello()
或將a
定義為類型B
的對象( B a = new C();
)。 這是因為編譯器正在跟蹤可用的方法。 如果由於某種原因您實際上沒有訪問實例化的權限,但是您需要訪問B
某些內容,但是將其作為A
對象傳遞給您,則可以進行強制轉換:
if (a instanceof B) (B a).hello();
else throw new Exception();
這都是關於變量類型的。 您正在實例化C類,但將結果對象視為A。A類的接口不包含“ hello”方法,這就是為什么您不能在示例中使用它的原因。
要解決該問題,您應該將方法添加到A或將變量的類型更新為B。
當您將變量聲明為具有超類的類型時,您只能通過該變量訪問(公共)方法和超類的成員變量。
在您的問題中A是B的父類,B是C的父類(即A-> B-> C),並且您通過A創建C類的對象。 因此,首先根據您的程序,它嘗試在A類中找到hello()方法,因為它是C的超父類,未定義hello()方法,這就是它顯示錯誤的原因。
我認為您對多態性的工作方式有些困惑。 您是說“ a”是“ c”對象,這是許多初學者所做的誤導性假設。 因此,以下示例說明了正在發生的事情:
假設您有一個“動物”類,該類通過單獨的“狗”類進行了擴展,因為狗是動物。 所以我們可以這樣寫:
Animal someAnimal = new Dog();
上面的語句可以改寫為:
Dog someDog = new Dog();
Animal someAnimal = someDog;
這表明Dog對象可以存儲為Animal對象。 為什么? 因為狗是動物。 你做不到
Dog someDog = new Animal();
因為“動物”不一定是“狗”。
這指向您的原始斷言。 您的“ a”不是“ c”對象,因為您從未寫過以下內容:
C a = new A(); // sidenote : this will give you error, as you are saying the analogous Animal is a Dog
結果,您的超類(“ A”)無法訪問子類(在本例中為“ B”)中的方法,因為超類不繼承自子類(反之亦然)。
在方法重寫中,您應該在超類中具有相同的方法。在這種情況下,大多數超類是A
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.