杰瑞科技汇

abstract方法为何必须声明在抽象类中?

abstract(抽象)是 Java 中一个非常重要的关键字,它用于定义抽象方法和抽象类,是实现多态和设计模式(如模板方法模式)的核心机制之一。

abstract方法为何必须声明在抽象类中?-图1
(图片来源网络,侵删)

什么是抽象方法?

抽象方法是一种没有具体实现(没有方法体)的方法,它只声明了方法的签名(方法名、参数列表和返回类型),但没有 括号中的代码。

语法格式:

[访问修饰符] abstract 返回类型 方法名(参数列表);

关键点:

  • 必须以 abstract 关键字开头。
  • 没有方法体,即分号 而不是 。
  • 必须存在于抽象类中(或接口中,但接口中的方法默认是抽象的,从 Java 8 开始可以有默认实现)。

示例:

abstract方法为何必须声明在抽象类中?-图2
(图片来源网络,侵删)
public abstract class Animal {
    // 这是一个抽象方法
    public abstract void makeSound(); // 只有声明,没有实现
    // 这是一个普通方法,有具体实现
    public void eat() {
        System.out.println("This animal is eating.");
    }
}

抽象方法的作用和意义

抽象方法的核心作用是定义一个“契约”或“规范”,它告诉所有继承这个抽象类的子类:“你们都必须实现 makeSound() 这个方法,但我不管你们具体怎么实现(是“汪汪叫”还是“喵喵叫”)”。

这带来了几个关键好处:

  1. 强制子类实现:如果一个非抽象类继承了一个抽象类,那么它必须为父类中的所有抽象方法提供具体的实现,否则,这个子类也必须被声明为 abstract
  2. 实现多态:通过抽象方法,我们可以定义一个通用的接口(父类引用),然后让不同的子类用自己的方式来实现这个接口,这使得代码更加灵活和可扩展。
  3. 建立模板:抽象类可以看作是一个“模板”,它定义了所有子类共有的属性和行为(普通方法),同时规定了一些子类必须具备的、但具体实现不同的行为(抽象方法)。

抽象类

抽象类是使用 abstract 关键字修饰的类,它不仅可以包含抽象方法,也可以包含普通方法、构造方法、字段和静态方法。

关键规则:

abstract方法为何必须声明在抽象类中?-图3
(图片来源网络,侵删)
  1. 不能被实例化:你不能直接创建一个抽象类的对象。new Animal(); 是错误的,这符合逻辑,因为一个抽象类代表的是一个不完整的概念(动物”不是一个具体的动物),你不能直接创建一个不完整的对象。
  2. 子类的责任
    • 如果一个非抽象类继承了一个抽象类,它必须实现(重写)父类中的所有抽象方法。
    • 如果一个子类不想或不能实现所有抽象方法,那么它自己也必须被声明为 abstract

示例:

定义抽象类 Animal

public abstract class Animal {
    // 抽象方法,子类必须实现
    public abstract void makeSound();
    // 普通方法,子类可以直接继承使用
    public void sleep() {
        System.out.println("This animal is sleeping.");
    }
}

创建具体的子类 Dog 并实现抽象方法

public class Dog extends Animal {
    // 必须实现父类的抽象方法
    @Override
    public void makeSound() {
        System.out.println("Woof! Woof!");
    }
}

创建具体的子类 Cat 并实现抽象方法

public class Cat extends Animal {
    // 必须实现父类的抽象方法
    @Override
    public void makeSound() {
        System.out.println("Meow!");
    }
}

使用多态

public class Main {
    public static void main(String[] args) {
        // Animal animal = new Animal(); // 错误!不能实例化抽象类
        // 使用父类引用指向子类对象(多态)
        Animal myDog = new Dog();
        Animal myCat = new Cat();
        myDog.makeSound(); // 输出: Woof! Woof!
        myDog.sleep();     // 输出: This animal is sleeping.
        myCat.makeSound(); // 输出: Meow!
        myCat.sleep();     // 输出: This animal is sleeping.
    }
}

抽象类 vs. 接口

这是一个非常经典且重要的问题,在 Java 8 之前,抽象类和接口有明确的区别,Java 8 引入默认方法和静态方法后,它们的界限变得模糊,但核心设计理念仍有不同。

特性 抽象类 接口
方法实现 可以包含抽象方法具体方法(有方法体)。 从 Java 8 开始,可以包含默认方法静态方法(有方法体),抽象方法默认是 public abstract
字段 可以包含各种类型的字段(public, protected, private, static, final),不一定是 public static final 字段隐式为 public static final(常量)。
构造方法 构造方法,虽然不能直接实例化,但子类在构造时会调用父类的构造方法。 没有构造方法。
继承 单继承,一个类只能继承一个抽象类。 多实现,一个类可以实现多个接口。
设计目的 "is-a" (是一个) 的关系,表示子类是父类的一种特例,共享代码和状态,它是一个模板,定义了基本行为。 "can-do" (能做) 的关系,表示一个类具备某种能力(行为),是一种契约或规范,它更像是一个角色。

如何选择?

  • 当多个类共享代码和状态,并且它们之间是“是一个”的关系时,使用抽象类。
    • DogCat 都是 Animal 的一种。Animal 可以有 name 字段和 sleep() 方法。
  • 当你想定义一个类的行为契约,并且希望一个类能够实现多个这样的契约时,使用接口。
    • 一个 Plane 和一个 Bird 都能 fly(),但它们没有共同的“是一个”关系。Flyable 接口定义了 fly() 行为。

  1. abstract 方法:只有声明,没有实现,用于定义规范。
  2. abstract:可以包含 abstract 方法和普通方法,但不能被实例化。
  3. 核心作用:强制子类实现特定方法,是实现多态和代码模板化的基础。
  4. 使用场景:当你希望创建一个基类,为子类提供一些通用的实现,同时又强制子类必须实现某些特定功能时,抽象类是理想的选择。
  5. 与接口的区别:抽象类强调“是什么”(is-a),共享代码和状态;接口强调“能做什么”(can-do),定义行为契约,支持多实现。

理解抽象方法是掌握 Java 面向对象编程和设计模式的关键一步。

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