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  阅读(14)  评论(0编辑  收藏  举报

👇