JavaSE4️⃣OOP - 抽象类 & 接口

1、面向抽象编程

含义:引用抽象类型,避免引用具体类型。

  1. 上层定义规范。
  2. 不同子类实现具体业务逻辑。
  3. 调用者只需关心接口定义,无需考虑具体实现。

实现方式

  1. 抽象类
  2. 接口

2、抽象类

2.1、abstract

含义

  1. 抽象类:无法被实例化,只能被继承的类。

    访问修饰符 abstract class 类名 {
    }
    
  2. 抽象方法:只定义方法签名,没有执行代码的方法。

    1. 使用场景:父类的方法本身不需要实现功能,目的是让子类重写。

    2. 作用:定义接口规范,面向抽象编程。

    3. 要求:抽象方法所在的类必须是抽象类。

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

注意

  1. 存在关系:有抽象方法必有抽象类,反之不成立。
    1. 抽象方法:必须声明在抽象类中。
    2. 抽象类:可以不声明抽象方法,可以声明普通方法。
  2. 抽象类的子类:根据其是否实现了所有的抽象方法。
    1. 是:普通类。
    2. 否:必须定义为抽象类,由其子类实现抽象方法。

2.2、应用示例

👉 OOP 三大特性 3.2.3

需求示例:实现一个税额计算方法,计算每种收入的税额。

假定有普通类型、工资类型、免税类型。

抽象类 & 抽象方法

定义抽象方法,无需实现。

public abstract class Income {
    protected double income;
    
    public abstract double getTax();
}

调用者

无需关心实现类,只需专注于目标功能。

public double totalTax(Income... imcomes) {
    double total = 0.0;
    for (Income income : imcomes) {
        total += income.getTax();
    }
    
    return total;
}

子类

实现父类中定义的抽象方法。

class GeneralIncome extends Income {
    @Override
    public double getTax() {
        // 税率10%
        return income * 0.1;
    }
}

class SalaryIncome extends Income {
    @Override
    public double getTax() {
        // 5000元起征
        return income <= 5000 ? 0 : (income - 5000) * 0.2;
    }
}

class TaxExemptIncome extends Income {
    @Override
    public double getTax() {
        // 免税
        return 0;
    }
}

3、接口

抽象类的本质是类,可定义成员变量、构造方法、普通方法和抽象方法。

若只定义抽象方法,不需要其它结构,则使用 Java 接口。

3.1、interface

3.1.1、语法

接口(interface):抽象方法的集合。

本身是一种抽象类型。

  1. 定义接口:

    1. 接口:使用关键字 interface 定义,指定接口名。

    2. 接口方法:默认使用 public abstract 修饰。

      public interface 接口名 {
          [public abstract] 返回值类型 方法名(参数列表);
      }
      
  2. 实现接口:

    1. 实现类:使用 implements 实现接口,作为实现类。

    2. 要求:必须实现所有抽象接口,否则需要定义为抽象类。

      class 类名 implements 接口名 {
          // 实现了所有抽象方法
      }
      
      abstract class 类名 implements 接口名 {
          // 存在未实现的抽象方法
      }
      

3.1.2、术语区分

接口

  • Java 接口:特指 interface 的概念。
  • 编程接口:泛指接口规范(如方法签名、数据格式、网络协议)。

重写/实现

类和接口中都有这两个概念,均使用 @override 注解。

假设已有方法 A,方法 B 对其重写或实现。

  • 重写:A 已定义方法体,B 对其逻辑进行重写。
  • 实现:A 仅定义方法签名,B 负责实现逻辑。

3.2、特点

  1. 多实现:Java 类只能继承自一个类,但可以实现多个接口。
  2. 多继承:
    1. 一个接口可以继承自另一个接口。
    2. 接口之间可以是多继承关系。

3.3、版本功能

随着 Java 版本更新,针对接口引入的新功能。

Java 7

全局静态常量

接口中可以定义成员变量,但只能是全局静态常量。

[public static final ]变量类型 变量名 = 常量值;
  1. 类型:public static final,无需显式声明。
  2. 特点:即静态(static)常量(final)的特点。

Java 8

默认方法(default)

提供方法默认实现,避免所有实现类都需要修改代码。

[public ]default 返回值类型 方法名(参数) {
    // 方法体
}
  1. 类型:
    1. 使用 default 修饰。
    2. public,无需显式声明。
  2. 特点:
    1. 需要提供方法实现。
    2. 不强制实现类进行重写,但可以重写。

静态方法(static)

提供方法实现,类似全局方法。

[public ]static 返回值类型 方法名(参数) {
    // 方法体
}
  1. 类型:
    1. 使用 static 修饰。
    2. public,无需显式声明。
  2. 特点:
    1. 需要提供方法实现。
    2. 通过接口名调用,而不是实现类名称。

Java 9

私有方法

提供方法实现,仅接口内部可访问。

// 私有方法
private 返回值类型 方法名(参数) {
    // 方法体
}

// 私有静态方法
private static 返回值类型 方法名(参数) {
    // 方法体
}
  1. 类型:
    1. 使用 private 修饰。
    2. 若声明为静态,则使用 private static 修饰。
  2. 特点:
    1. 需要提供方法实现。
    2. 接口内部才能访问。

4、抽象类 vs 接口

4.1、对比

相同点

  1. 多态。
  2. 面向抽象编程。
  3. 不能直接实例化,需实现所有抽象方法。

不同点

从类和接口的区别理解。

抽象类 接口
构造方法 有 无
成员变量 任意类型 public static final
方法 普通方法、抽象方法 抽象方法
继承 单继承 多实现,多继承
抽象程度 - 接口比抽象类更抽象

4.2、最佳实践

原则:接口定义行为,类定义逻辑。

  1. 接口定义行为规范,层次代表抽象程度。
  2. 抽象类处理公共逻辑,子类实现具体逻辑。
  3. 调用者引用接口类型,而不是引用抽象类或具体子类型。

示例:Java 集合

┌───────────────┐
│   Iterable    │
└───────────────┘
        ▲                ┌───────────────────┐
        │                │      Object       │
┌───────────────┐        └───────────────────┘
│  Collection   │                  ▲
└───────────────┘                  │
        ▲     ▲          ┌───────────────────┐
        │     └──────────│AbstractCollection │
┌───────────────┐        └───────────────────┘
│     List      │                  ▲
└───────────────┘                  │
              ▲          ┌───────────────────┐
              └──────────│   AbstractList    │
                         └───────────────────┘
                                   ▲
                                   │
                                   │
                             ┌────────────┐
                             │ ArrayList  │
                             └────────────┘
public static void main(String[] args) {
    List list = new ArrayList();
	handle(list);	// 自动向上转型
}

// 调用者:通过接口类型引用
public static void handle(Iterable it) {
}
posted @ 2023-02-10 00:33  Jaywee  阅读(80)  评论(0)    收藏  举报

☝

👇