2017-07-28 57 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抽象类;或者只是使用组合,但这不在这个问题的范围之内)。

相关问题