簡體   English   中英

有關多態性的Java接口問題

[英]Java Interface question regarding polymorphism

所以我有這個:

interface C {
    void shutUp();
}

class A {
    public void speak() {
       System.out.println("Class a");
    }
}

class B extends A implements C {
    public void shutUp() {
        System.out.println("Saying nothing...");
    }

    public void speak() {
        System.out.println("Class B");
    }
}

如果我這樣做,它將起作用:

A obj = new B();
obj.speak()

但是我不能做obj.shutUp()為什么不呢? 我覺得我對一些非常基本的東西感到困惑。

謝謝!

A的靜態類型未連接到C,因此您無法執行此命令,這將是相同的:

A obj = new A();
obj.shutUp();

(這顯然是非法的。)
唯一可以同時使用兩者的人是B

B obj = new B();
obj.shutUp();
obj.speak();

這都與Java是static typing這一事實有關

因為A不是C-它沒有實現接口-並且您不能以這種方式實例化接口,因為沒有默認的構造函數。

類型A的引用沒有方法shutUp() ,因此它不起作用也就不足為奇了。

而且您的代碼使用了錯誤的關鍵字:這是Java的classinterface 案件很重要。

通過說A obj = new B(); 您正在將代碼與接口的特定實現分離。 因此,obj將無法訪問在類b中實現的shutup()函數。

您的obj具有類A接口,因為它是變量的類型。

obj的類型定義為A 因此, obj只能使用A可用的成員。 因為C繼承自A ,所以C具有被視為A形式的所有成員,這就是為什么它允許您在A變量中創建新C的原因。 只有將其強制轉換為C類型,您才能使用屬於C所有成員。

您的問題是錯誤的:您無法創建C對象,因為它是接口-所以我認為您想創建B對象,然后:

這是因為obj是A而不是C,要使用shutUp方法,您可以:

((C) obj).shutUp() // cast to C type
((B) obj).shutUp() // cast to B type

或聲明:

B obj = new B();
obj.shutUp();

要么:

C obj = new B(); // (!) but: you can't (without casting) call speak method
obj.shutUp();

obj =新的C();

因為C是接口,所以您不能創建接口的實例。 請更正問題。

為什么不能在obj上調用shutUp的原因是:

obj不是對象,而是指針或引用。 執行新B()時創建的對象是一回事,obj(或“如何使用該對象”)是另一回事。 您可以在引用(在本例中為obj)的幫助下使用對象,該引用使您可以訪問實際對象的不同側面。

如果用於訪問對象的引用是引用當前對象的類型(即,具有相同的名稱),則可以通過此引用訪問整個對象。 否則,您只能訪問引用類型可以看到的對象部分。

在您的示例中,引用類型為A,即obj僅看到其引用的任何對象的A部分。 因此,即使對象具有這些行為,它也無法訪問對象的B / C部分。

其他人已經回答了這個問題,但是請注意,有一種方法可以在不強制轉換為BC情況下調用shutUp()

A obj = new B();
try {
    Method shutUp = obj.getClass().getMethod("shutUp", null);
    shutUp.invoke(obj, null);
}
catch (Exception ignored) {}
A obj = new B();

在這里,您將創建類型為“ A”的“ B”實例。 即,您說的是“我想創建一個對象B並將其命名為類型A的obj”。

在A類中,只有一種可訪問的方法。 它沒有實現C

public void speak() {}

為了能夠訪問類B的所有方法,您應該創建“ B”類型的“ B”實例

B obj2 = new B();

這樣您就可以訪問

 public void shutUp() {}

這是因為實現類“ C”的是B。

能夠使用“ obj”訪問這兩種方法的一種方法是使A工具C

new B()創建的對象可用作三種類型的對象-A,B或C。但是您不能聲明多種類型的變量。

由於B是A和C的子類型,因此您可以將其實例用作任何這些類型的實例。 例如

B o = new B();
A aO = o;
C cO = o;

現在你可以使用o來訪問speakshutUp方法,您可以使用aO訪問speak方法和cO訪問shutUp方法。 不管使用哪個變量,調用的方法都是相同的,因為這些變量都引用相同的對象。 為什么不能使用aO來調用Java中的shutUp原因是因為您使用沒有這種方法的類型聲明了變量。 盡管您知道該特定對象確實具有該方法,但一般而言並非如此。

class D extends A {
    public void speak(){
        System.out.println("Class D");
    }
}

List<A> as = new ArrayList<A>();
as.add(new A());
as.add(new B());
as.add(new D());

A a0 = as.get(0);
A a1 = as.get(1);
A a2 = as.get(2);

a0.speak(); // >> Class A
a1.speak(); // >> Class B
a2.speak(); // >> Class D 

現在,在此示例中,單個集合中包含三個不同類的實例。 當您傳遞或修改此集合時,您將永遠不知道每個對象實際上是哪個類。 您所知道的都是它們都是A類型的,盡管實際上它們可以是A的任何子類型(例如B或D),但它們一定是該類型的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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