为什么扩展抽象 class 来更改函数定义,当我可以简单地使用方法覆盖时?

Why extend abstract class to change function definition, when I can simply use method overriding?

假设我有一只动物 class,并且我希望每种动物都有不同的 classes 和功能。有两种方法可以做到这一点:

  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 摘要 class:

    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();
    }
    

那么,当第一种方法完成完全相同的事情时,为什么我们要使用抽象 classes 呢?我理解为什么我们使用接口 - 它建立了一个契约,任何 class 实现它都必须具有特定的方法和属性。但是,如果通过简单的继承就可以实现同样的事情,那么抽象 class 有什么用呢?

关于抽象 class 的重要一点 - 它 无法实例化 。因此,根据您的问题的性质,有时您会想要使用它。

动物实际上就是一个很好的例子:

因为世界上没有个动物,但是特定的只有动物。所以 - 你会想要一个抽象 class Animal 和特定的动物 classes 将扩展它,并实现它的抽象方法。

此外,您可以在抽象 class 非抽象方法中使用这些方法 - 当扩展它的每个 class 都有 shared/common 行为时,您可以使用这些方法。

有一些基本概念因不使 Animal 抽象或接口而被破坏。我推荐你阅读 here.

举个例子说明为什么你发布的层次结构在你的场景中是错误的。任何人都可以这样做:

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

完全没有意义; animal 在您的场景中是抽象的,而不是具体的。您不应该能够实例化 "Animal",而是它的具体实现之一。

另外,从你的场景来看,Animal应该是一个接口。它没有提供任何由其子级共享的通用实现(即使是,我也会将 Animal 保留为接口并且只有一个 BaseAnimal 抽象 class;或者只是使用组合,但这超出了这个问题的范围).