【问题标题】:Why extend abstract class to change function definition, when I can simply use method overriding?当我可以简单地使用方法覆盖时,为什么要扩展抽象类来更改函数定义?
【发布时间】:2026-01-29 19:55:01
【问题描述】:

假设我有一个 Animal 类,我希望每种动物都有不同的类和功能。有两种方法可以做到这一点:

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

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

【问题讨论】:

  • 同样的事情?因此,如果您不在Dog 中创建sound(),那么在这两个版本中会发生什么?显然不一样。这告诉你为什么abstract 在大多数情况下更好。
  • 使用abstract 类,你有两种类型的函数:有和没有abstract 关键字。使用abstract 关键字强制所有子类必须实现此方法。如果没有abstract 关键字,您可以在父级自行实现此方法,如果需要,您可以在每个子级上覆盖或使用父级的实现。如果使用Interface那么你不能实现一个方法,每个孩子必须自己实现它。
  • 在第一种情况下你必须实现Animal中的方法,但在第二种情况下你不需要。此外,抽象类不是在内存中创建的,请参见此处:*.com/questions/20756679/…
  • 如果Animal 是一个不完整的类,那么您不希望客户端能够创建它的实例。您通过使其抽象来表示这一点。在案例 1 中,客户可以执行Animal a = new Animal();。在情况 2 中,这将被编译器捕获。
  • 必须实现抽象函数。父方法没有。这就是区别。此外,抽象类不能被实例化。你可以用私有构造函数创建一个类,但是当你有抽象类时为什么要这样做

标签: java oop inheritance abstract-class abstract


【解决方案1】:

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

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

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

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

【讨论】:

  • 我明白你的意思。你能举一个类似的例子,使用覆盖和继承而不是使用抽象类会更好吗?
  • @lebowski 我想你误解了——当你有一个抽象类时,你既可以继承它也可以覆盖它。抽象类和接口之间的主要区别在于抽象类可以提供方法的默认实现,然后您可以覆盖这些实现。
  • 当然。一个例子是基类和扩展类都可以被实例化的上下文——比如RectangleSquare。两者都存在于世界上,但square只是一个特定的rectangle,具有更多的特点。
  • @SHG 这些是一些非常好的例子,这无疑消除了我的一些困惑。将您的答案标记为已接受。
【解决方案2】:

没有使 Animal 抽象或接口破坏了基本概念。我建议你阅读here

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

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

这根本没有意义;在您的场景中,动物是抽象的,而不是具体的。您不应实例化“Animal”,而是实例化其具体实现之一。

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

【讨论】:

    最近更新 更多