2017-07-28 49 views
1

說我有一個動物類,我想爲每種動物不同的類和功能。這樣做有兩種方式:通過繼承爲什麼擴展抽象類來改變函數定義,當我可以簡單地使用方法覆蓋?

  1. 方法覆蓋:

    public class Animal { 
        public void sound() {} 
    } 
    
    public class Dog extends Animal { 
        public void sound() { 
         System.out.println("bark"); 
        } 
    } 
    
    public static void main(String[] args) { 
        Animal dog = new Dog(); 
        dog.sound(); 
    } 
    
  2. 通過擴展Animal抽象類:

    abstract public class Animal { 
        abstract public void sound(); 
    } 
    
    public class Dog extends Animal { 
        public void sound() { 
         System.out.println("bark"); 
        } 
    } 
    
    public static void main(String[] args) { 
        Dog dog = new Dog(); 
        dog.sound(); 
    } 
    

那麼,爲什麼我們使用抽象類什麼時候,第一種方法完成同樣的事情?我明白爲什麼我們使用接口 - 它建立了一個合同,任何實現它的類都必須具有某些方法和屬性。但是,如果通過簡單繼承可以實現同樣的事情,那麼抽象類的用法是什麼?

+1

同樣的事情?所以如果你不在'Dog'中創建一個'sound()',那麼這兩個版本會發生什麼?顯然不一樣。這就告訴你爲什麼'abstract'在大多數情況下更好。 – Tom

+0

使用'抽象'類你有2種類型的函數:有和沒有'抽象'關鍵字。用'abstract'關鍵字強制所有的子類必須實現這個方法。如果沒有'abstract'關鍵字,你可以在父母,子女上自行實現這個方法,如果需要的話你可以覆蓋每個孩子,或者可以使用父母的實現。如果使用'Interface',那麼你不能實現一個方法,每個孩子都必須自己實現它。 –

+0

在第一種情況下,您必須在'Animal'中實現該方法,但在第二種情況下您不需要。另外,抽象類不是在內存中創建的,請參見:https://stackoverflow.com/questions/20756679/how-jvm-handles-abstract-class-in-java – tima

回答

5

關於抽象類的一件重要事情 - 它不能實例化。因此,根據問題的性質,有時您會想要使用它。

的動物實際上是一個很好的例子:

由於沒有情況下,在世界動物,但實例具體只動物。所以 - 你會想要一個抽象類Animal,特定的動物類將擴展它,並實現其抽象方法。另外,你可以在抽象類中使用非抽象方法 - 當每個擴展它的類都有共享/共同行爲時,你會使用這些方法。

+0

我明白你的意思了。你能否給出一個類似的例子,使用覆蓋和繼承,而不是使用抽象類更好? – lebowski

+1

@lebowski我認爲你誤解了 - 當你有一個抽象類時,你可以從它繼承並覆蓋它。抽象類和接口之間的一個主要區別是抽象類可以提供方法的_default_實現,然後您可以覆蓋它們。 –

+1

當然。一個例子就是這樣一個上下文,其中基類和擴展類都可以實例化 - 比方說'矩形'和'方形'。它們都存在於世界上,但「方形」只是一個特定的「矩形」,具有更多的特徵。 – SHG

2

有一些基本概念由於沒有製作動物摘要或界面而被破壞。我建議你閱讀here

就像您的方案中發佈層次結構錯誤的一個例子。任何人都可以這樣做:

Animal noanimal = new Animal(); 
noanimal.sound(); 

根本沒有意義;動物在你的場景中是抽象的,而不是具體的。你不應該能夠實例化「動物」,而是它的具體實現之一。

另外,從您的場景看,動物應該是一個界面。它沒有提供任何通用的實現來被其子進程所共享(即使它是,我將Animal作爲接口並且只有一個BaseAnimal抽象類;或者只是使用組合,但這不在這個問題的範圍之內)。

相關問題