簡體   English   中英

為什么子類看不到父類的方法?

[英]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.

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