参考资料::黑马程序员·入门到飞起上

1.1 概述

1.1.1 抽象类引入

在面向对象编程中,当父类中的方法被子类重写,且子类各自的实现方式差异较大时,父类方法的声明具有通用的指导意义,但方法主体可能不再适用于所有子类。此时,父类虽知道子类应具备某个功能,却不清楚具体的实现方式,这一实现过程应由子类自行决定。因此,父类只需提供一个没有方法体的方法定义,将具体实现留给子类这种没有方法体的方法被称为抽象方法在Java语法中,包含抽象方法的类即为抽象类

  • 抽象方法:指的是仅有方法声明,而无方法体的方法。
  • 抽象类:包含抽象方法的类被定义为抽象类。

1.2 abstract使用格式

“abstract”在Java中表示抽象的含义,可用于修饰方法和类。当修饰方法时,该方法成为抽象方法;修饰类时,该类则成为抽象类。

1.2.1 抽象方法

使用abstract关键字修饰方法,该方法便成为抽象方法。抽象方法仅包含方法名,不包含方法体。其定义格式如下:

修饰符 abstract 返回值类型 方法名 (参数列表);

例如:

public abstract void run();

1.2.2 抽象类

若一个类包含抽象方法,那么这个类必须被声明为抽象类。需要注意的是,抽象类不一定都含有抽象方法,但只要类中存在抽象方法,就必须将其定义为抽象类。抽象类的定义格式如下:

abstract class 类名字 { 
  
}

示例代码如下:

public abstract class Animal {
    public abstract void run();
}

1.2.3 抽象类的使用

继承抽象类的子类必须重写父类中的所有抽象方法,否则该子类同样必须声明为抽象类。以下通过具体代码示例说明:

// 父类,抽象类
abstract class Employee {
    private String id;
    private String name;
    private double salary;
    
    //空参构造
    public Employee() {
    }
    //全参构造
    public Employee(String id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    // 抽象方法
    // 抽象方法必须要放在抽象类中
    abstract public void work();
}

// 定义一个子类继承抽象类
class Manager extends Employee {
    public Manager() {
    }

    public Manager(String id, String name, double salary) {
        super(id, name, salary);//调用父类的构造方法
    }

    // 2.重写父类的抽象方法
    @Override
    public void work() {
        System.out.println("管理其他人");
    }
}

// 定义一个子类继承抽象类
class Cook extends Employee {
    public Cook() {
    }

    public Cook(String id, String name, double salary) {
        super(id, name, salary);
    }

    @Override
    public void work() {
        System.out.println("厨师炒菜多加点盐...");
    }
}

// 测试类
public class Demo10 {
    public static void main(String[] args) {
        // 创建抽象类,抽象类不能创建对象
        // 假设抽象类让我们创建对象,里面的抽象方法没有方法体,无法执行.所以不让我们创建对象
//      Employee e = new Employee();
//      e.work();

        // 3.创建子类
        Manager m = new Manager();
        m.work();

        Cook c = new Cook("ap002", "库克", 1);
        c.work();
    }
}

在上述代码中,子类对父类抽象方法的完整实现过程,也被称为“实现方法”。

1.3 抽象类的特征

抽象类的特征可以概括为“有得有失”:

  • 有得:抽象类获得了定义抽象方法的能力,从而为子类提供了一种通用的行为规范或接口,使得子类在继承抽象类时,必须按照抽象类定义的规则实现具体的功能。
  • 有失:抽象类失去了直接创建对象的能力。这是因为抽象类中可能包含未实现的抽象方法,如果允许创建抽象类的对象,在调用这些抽象方法时将无法执行具体的操作,因此Java语言禁止创建抽象类的对象。

此外,抽象类与普通类一样,具备构造方法、实例方法、静态方法等其他成员。

1.4 抽象类的细节

在使用抽象类时,有一些语法细节需要注意。这些细节无需刻意记忆,当在开发工具(如IDEA)中出现报错时,能够明白如何修改即可。理解这些细节的关键在于把握抽象类的本质。

  1. 抽象类不能创建对象:试图创建抽象类的对象会导致编译错误。这是因为抽象类中的抽象方法没有具体的实现,若创建对象并调用抽象方法,将无法执行有效的操作。只有其非抽象子类才能创建对象,通过子类对象调用重写后的具体方法来实现相应功能。
  2. 抽象类中可以有构造方法:抽象类中的构造方法主要用于供子类在创建对象时初始化父类成员。在子类的构造方法中,默认会调用super()来访问父类的构造方法,以确保父类成员能够正确初始化。
  3. 抽象类不一定包含抽象方法,但有抽象方法的类必定是抽象类:即使一个抽象类中不包含抽象方法,它仍然具有存在的价值。这种情况下,抽象类的目的通常是限制调用者创建该类的对象,常用于特定的类结构设计,例如为一组相关的子类提供一个统一的抽象基类,便于进行类型管理和多态操作。
  4. 抽象类的子类必须重写抽象父类中的所有抽象方法:否则,子类必须也定义为抽象类,否则会导致编译错误。这是因为如果子类不重写所有抽象方法,那么该子类可能仍然包含抽象方法,创建此类对象并调用抽象方法将没有实际意义。通过强制子类重写抽象方法,保证了子类具有具体的行为实现。
  5. 抽象类存在的意义是为了被子类继承:抽象类定义了一组子类共同遵循的模板,其中已经实现的部分是模板中确定的成员,而对于不确定如何实现的部分,则定义成抽象方法,由具体的子类根据自身需求去实现。这样可以提高代码的复用性和可扩展性,同时确保子类之间具有一定的一致性和规范性。

1.5 抽象类存在的意义

抽象类存在的核心意义在于为子类提供一个可继承的基础框架,强制子类按照特定的格式进行方法重写。通过抽象类,我们可以将一些具有共性的行为和属性抽象出来,避免在子类中重复实现,提高代码的复用性。同时,抽象类定义的抽象方法为子类提供了明确的行为规范,使得不同的子类能够以统一的方式进行操作,增强了代码的可维护性和扩展性。如果没有子类继承,抽象类的存在将失去实际意义。