杰瑞科技汇

Java为何允许没有抽象方法的抽象类?

可以。

Java为何允许没有抽象方法的抽象类?-图1
(图片来源网络,侵删)

在 Java 中,一个类被声明为 abstract,即使它没有任何 abstract 方法,它也是一个抽象类,这种做法是完全合法且有其特定用途的。


核心概念

一个抽象类,无论是否包含抽象方法,其最核心的特性是:它不能被直接实例化,你不能用 new 关键字来创建一个抽象类的对象。

abstract 关键字的作用是禁止类的实例化,从而强制该类必须被继承,这为类的设计提供了强制性的约束。


为什么要有没有抽象方法的抽象类?

虽然抽象方法(abstract method)是抽象类最常见的用途,但一个没有抽象方法的抽象类同样非常有用,其主要目的可以归结为以下几点:

Java为何允许没有抽象方法的抽象类?-图2
(图片来源网络,侵删)

防止实例化,实现“纯”基类或工具类

这是最常见和最直接的原因,你设计一个类只是为了作为其他类的基类,或者它是一个包含静态方法和静态字段的工具类,你不希望任何人错误地创建这个类的实例,因为它本身不表示一个完整、独立的实体。

示例:一个工具类

// 这是一个工具类,提供了一些通用的数学计算方法
// 它本身不应该被实例化,因为创建一个 MathUtils 对象没有意义
public abstract class MathUtils {
    // 私有构造函数,防止被外部实例化
    // 这是另一种防止实例化的方式,但使用 abstract 关键字更明确地表达了设计意图
    private MathUtils() {}
    public static int add(int a, int b) {
        return a + b;
    }
    public static int subtract(int a, int b) {
        return a - b;
    }
    public static double power(double base, int exponent) {
        return Math.pow(base, exponent);
    }
}
// 尝试实例化会导致编译错误
// MathUtils utils = new MathUtils(); // 编译错误: MathUtils is abstract; cannot be instantiated

为什么用 abstract 而不是私有构造函数?

  • 设计意图更清晰:使用 abstract 关键字,其他开发者一眼就能看出这个类是设计用来被继承的,或者它是一个抽象基类,而不是一个普通的工具类。
  • 强制子类化:即使一个类没有抽象方法,任何试图继承它的子类仍然需要实现其父类中不存在的抽象方法(如果父类有的话),但对于没有抽象方法的抽象类,子类可以正常继承和使用。

为未来的扩展预留空间

你可能正在设计一个基类,但目前它的所有方法都是具体实现,但你预计未来可能会有一些变化,或者你想确保这个基类在未来被继承时,某些行为需要被覆盖,将它声明为 abstract 可以确保它不会被错误地用作独立对象,并为未来的修改提供了灵活性。

Java为何允许没有抽象方法的抽象类?-图3
(图片来源网络,侵删)

示例:一个图形基类

public abstract class Shape {
    private String color;
    public Shape(String color) {
        this.color = color;
    }
    // 这是一个具体方法,所有子类都会默认使用这个实现
    public String getColor() {
        return color;
    }
    // 这是一个具体方法,但逻辑很简单,子类可以选择覆盖它
    public void displayInfo() {
        System.out.println("This is a shape with color: " + color);
    }
    // 假设我们未来可能想添加一个需要子类实现的抽象方法
    // public abstract double getArea(); // 未来可能会添加
}
// 子类可以正常继承
public class Circle extends Shape {
    private double radius;
    public Circle(String color, double radius) {
        super(color);
        this.radius = radius;
    }
    @Override
    public void displayInfo() {
        super.displayInfo();
        System.out.println("This circle has a radius of: " + radius);
    }
}
// 使用
Circle myCircle = new Circle("Red", 5.0);
myCircle.displayInfo();
// 输出:
// This is a shape with color: Red
// This circle has a radius of: 5.0

在这个例子中,Shape 类目前没有抽象方法,但它被声明为 abstract,表明它是一个基类,并且为将来可能添加的抽象方法(如 getArea())做好了准备。

实现模板方法设计模式的一部分

在模板方法模式中,一个抽象类定义了一个算法的骨架(由具体方法组成),而其中一些步骤可能由抽象方法定义,由子类实现,即使算法的所有步骤都是具体的,将整个类声明为 abstract 也可以确保它只作为模板存在,而不是一个独立的、可运行的实体。


特性 有抽象方法的抽象类 没有抽象方法的抽象类
能否实例化 不能 不能
主要目的 定义一个契约,强制子类必须实现某些方法。 防止实例化,明确其作为基类或工具类的角色。
设计意图 强制子类化以完成特定行为。 防止误用,为未来扩展预留空间,或组织代码结构。
示例 Animal 类有 makeSound() 抽象方法,DogCat 必须实现它。 MathUtils 工具类,或一个预留扩展的 Shape 基类。

Java 允许存在没有抽象方法的抽象类,这并非矛盾或冗余,而是面向对象设计中一种非常强大和有用的技术,它通过禁止实例化这一简单规则,来强制类的继承关系,从而提高代码的健壮性、可维护性和设计清晰度,当你设计一个不应该被独立使用的基类或工具类时,将其声明为 abstract 是一个非常好的实践。

分享:
扫描分享到社交APP
上一篇
下一篇