Advertisement

【Java基础笔记】第二十章 抽象类、接口

阅读量:

目录

抽象类案例

案例分析

模板方法模式案例

模板方法模式案例

基于抽象类的实现:模板方法模式

  • 20.3 接口(暂无特殊说明)
    • 20.3.1 接口概述介绍
  • 20.3.2 对接口进行形式化定义
  • 20.3.3 分析接口的主要特性
  • 20.3.4 解释接口的应用场景
  • 20.3.5 提供实现接口时需要注意的关键点
  • 20.3.6 比较不同接口之间的关联性
  • 20.3.7 自从JDK8版本开始增加了新的接口特性
    • 第一类:具有默认功能的方法(即无需显式声明即可执行的操作)

    • 第二类:完全静态的功能模块(仅能在单个类内调用)

    • 第三类:私有且仅限于内部使用的方法(仅在当前类内部可见)

      • 20.3.8 使用接口的注意事项

前言

该笔记作为Java基础自学的课程学习材料编写而成。
其他内容:点击阅读更多 Java基础学习笔记目录
学习资源:
《Java核心技术 卷Ⅰ 基础知识(第10版)》
《Java经典编程300例》

第二十章 抽象类、接口

20.1 抽象类

20.1.1 抽象类的概述

  • 某个父类认识到其所有子类均需实现某一特定功能;然而由于各子类的具体实现方式不尽相同;因此该父类只需规定该功能的基本要求;而具体实现细节则由各子 class 自行确定;这样的结构就可以定性为一个 abstract 类别;总体而言;abstract 类相当于一种未完成的设计框架。
  • abstract 类必须使用 abstract修饰:
复制代码
    修饰符 abstract class 类名() {...}
    
    
      
    
    代码解释

20.1.2 抽象方法的概述

  • 抽象类中定义的子类应具备完成其核心内容的基本职责。
  • 该抽象类未提供具体实现细节,仅声明了其方法声明。
  • 该抽象方法应采用abstract注解形式:
复制代码
    	修饰符 abstract 返回值类型 方法名称(形参列表);
    
    
      
    
    代码解释

20.1.3 抽象类的特征

  • 抽象类型可被继承的对象是abstract class。
  • 得到一个abstract method的同时失去了创建对象的能力。
  • 类所有的成员(包括成员变量、成员函数和构造函数)都是abstract class的基础属性。
  • 如果一个class不是abstract的话,则它不可能包含任何abstract method。
  • 如果一个class继承了abstract type,则该class必须完整地实现了其父级的所有abstract methods。
  • 不允许使用abstract修饰基元类型(如字段或代码块)。

20.1.4 final和abstract的关系

  • 互斥关系
    • abstract类型的抽象(abstract)类型作为模板供子(subclass)使用时能够继承其属性与行为(method),而final指定(final)的类型无法被任何其他(non-abstract)类型所继承
    • abstract方法提供的通用(abstract)功能能够让子(subclass)具体实现细节(implementation details),而final指定的方法则无法由其他任何方法来实现

【抽象类案例】贵宾卡系统

  • 需求: * 该加油站推出了两种类型的支付卡。其中一种是预存金额为1万元的金色系列支付卡,在加油时可享八折优惠待遇;另一种是预存金额为5千元的银色系列支付卡,在加油时可享八点五折优惠待遇
  • 请分别就这两种类型的支付卡设计其在收银系统中的处理流程。每张卡片需包含持卡人姓名、当前余额以及支持完成交易的功能

分析

  • 父类Crad:
复制代码
    public abstract class Card {
    private String name;
    private double balance;
    
    public abstract void pay(double money);
    
    public String getName() {
        return name;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    public double getBalance() {
        return balance;
    }
    
    public void setBalance(double balance) {
        this.balance = balance;
    }
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解释
  • 金卡类GoldCard:
复制代码
    public class GoldCard extends Card {
    @Override
    public void pay(double money) {
        money *= 0.8;
        double balance = getBalance() - money;
        System.out.println(getName() + "当前账户总金额:" + getBalance() + ",当前消费了:" + money + ",消费后的余额为" + balance);
        setBalance(balance);
    }
    }
    
    
      
      
      
      
      
      
      
      
      
    
    代码解释
  • 银卡类SilverCard: 同金卡
    • 测试类CardTest:
复制代码
    public class CardTest {
    public static void main(String[] args) {
        GoldCard goldCard = new GoldCard();
        goldCard.setBalance(10000);
        goldCard.setName("李明");
        goldCard.pay(800);
    }
    }
    
    
      
      
      
      
      
      
      
      
    
    代码解释
  • 测试结果:
复制代码
    李明当前账户总金额:10000.0,当前消费了:640.0,消费后的余额为9360.0
    
    
      
    
    代码解释

20.2 抽象类的应用:模板方法模式

20.2.1 模板方法模式使用场景

当系统中出现同一功能模块分散在多个地方时,在大多数情况下两者的代码是相同的

20.2.2 模板方法模式实现步骤

  • 将其归类为一种预先定义好的模板方法,并置于抽象类中进行处理。
  • 在这些模板方法的具体代码部分定义通用且明确的功能逻辑。
  • 对于那些未作具体决定的功能,在实现时将其转化为抽象的方法供子类继承和实现。
  • 在实现该模板方法时添加final关键字以防止子类重写。

【模板方法模式案例】银行利息结算系统

需求:

分析

  • 银行账户父类Account:
复制代码
    public abstract class Account {
    private static final String LOGIN_NAME = "admin";
    private static final String PASSWORD = "123456";
    
    private String cardId;
    private double money;
    
    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }
    
    /** * 模板方法添加final,避免被子类重写
     * @param loginName 登录名
     * @param password  密码
     */
    public final void handle(String loginName, String password) {
        if (loginName.equals(LOGIN_NAME) && password.equals(PASSWORD)) {
            //System.out.println("登录成功!");
            double result = calc();
            System.out.println("本账户利息是:" + result);
        } else {
            System.out.println("用户名或密码不正确!");
        }
    }
    
    public abstract double calc();
    
    public String getCardId() {
        return cardId;
    }
    
    public void setCardId(String cardId) {
        this.cardId = cardId;
    }
    
    public double getMoney() {
        return money;
    }
    
    public void setMoney(double money) {
        this.money = money;
    }
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解释
  • 活期账户类CurrentAccount:
复制代码
    public class CurrentAccount extends Account {
    
    private static final double CURRENT_RATE = 0.0035;
    
    public CurrentAccount(String cardId, double money) {
        super(cardId, money);
    }
    
    @Override
    public double calc() {
        return getMoney() * CURRENT_RATE;
    }
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解释
  • 定期账户类FixedAccount:
复制代码
    public class FixedAccount extends Account {
    
    private static final double FIXED_RATE = 0.0175;
    private static final double MONEY = 100000;
    private static final double EXTRA_RATE = 0.03;
    
    public FixedAccount(String cardId, double money) {
        super(cardId, money);
    }
    
    @Override
    public double calc() {
        double result = getMoney() * FIXED_RATE;
        if (getMoney() >= MONEY) {
            result += getMoney() * EXTRA_RATE;
        }
        return result;
    }
    }
    
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解释
  • 测试类TemplateTest:
复制代码
    public class TemplateTest {
    public static void main(String[] args) {
        CurrentAccount currentAccount = new CurrentAccount("ICBC01",100000);
        currentAccount.handle("admin","123456");
    
        FixedAccount fixedAccount = new FixedAccount("ICBC01",100000);
        fixedAccount.handle("admin","123456");
    }
    }
    
    
      
      
      
      
      
      
      
      
      
    
    代码解释
  • 测试结果:
复制代码
    本账户利息是:350.0
    本账户利息是:4750.0
    
    
      
      
    
    代码解释

20.3 接口(干爹)

注:继承是亲爹

20.3.1 接口的概述

接口即体现规范的方式,在此过程中具体表现为一组行为规范。这种设计使得接口成为更为彻底的抽象形式。

20.3.2 接口的定义

  • 接口用关键字interface来定义
复制代码
    public interface 接口名 {
    	// 常量
    	// 抽象方法
    }
    
    
      
      
      
      
    
    代码解释

20.3.3 接口的特点

  • 在JDK8版本之前的接口设计上仅允许包含虚函数(abstract methods)和静态常量(constant),没有任何其他类型的成员
  • 作为编程结构的一部分,接口本身不具备构造实例的能力
  • 在规范制定下,默认情况下所有接口成员都被标记为public修饰符(public),这确保了信息的一致性和可访问性
复制代码
    public interface demoInter {
    	// 常量(public static final可以省略不写,接口会默认加上)
    	String NAME = "李明";
    	// 抽象方法(public abstract可以省略不写,接口会默认加上)
    	void run();
    }
    
    
      
      
      
      
      
      
    
    代码解释

20.3.4 接口的用法

接口是用来被类满足(satisfies)相关功能的(corresponding),满足接口的类被称为实现者(implementor),而这些具有继承功能的(feature)的类别通常被称为继承类型(inheritance type)。

复制代码
    修饰符 class 实现类 implements 接口1,接口2,接口3,... {
    }
    
    
      
      
    
    代码解释
  • 接口可以被类单实现,也可以被类多实现

20.3.5 接口实现的注意事项

该类若要实现某个接口,则必须在其所有相关对象上实现相应的抽象方法;否则,则该类应定义为抽象类。

20.3.6 接口与接口的关系

  • 类型之间的关系: 类型之间采用单继承于一个父类型。
  • 类型与接口的关联: 类型能够实现多个不同的接口。
  • ** interfaces之间的关系: ** 支持多继承特性; 一个 interface 最多只能声明一个多 inherited interface.
  • ** interfaces 的多重继承作用: ** 规范整合、统一合并; 简化子 class 的实现过程。

20.3.7 JDK8开始接口新增方法

第一种:默认方法
  • 类似之前写的普通实例方法:必须通过default进行修饰
    • 默认情况下由public修饰,并需采用该接口的实际类对象来进行调用
复制代码
    	default 返回类型 方法名() {...}
    
    
      
    
    代码解释
第二种:静态方法
  • 通常情况下, 公共方法默认会采用static命名。
    • 特别说明: 当访问一个接口的静态方法时, 必须使用该接口自身的方法名来进行调用。
复制代码
    	static 返回类型 方法名() {...}
    
    
      
    
    代码解释
第三种:私有方法
  • 属于私有实例的方法:必须以private修饰,并自Java语言规范1.9起才被支持。
    • 只能被本接口中的其他默认方法或其他接口中的私有方法访问。
复制代码
    	private 返回类型 方法名() {...}
    
    
      
    
    代码解释
  • 三种方法很少在开发中使用,通常出现在Java源码中

20.3.8 使用接口的注意事项

  • 接口无法直接构造实例
    • 单一类型实例可同时满足多个需求
      • 继承父类的同时又实现了某个特定的API
        • 存在相同的默认值
          • 如果没有规范冲突(同名但返回类型不同的抽象操作)
            • 那么无需修改现有代码即可满足需求
            • 如果存在规范冲突(同名但返回类型不同的抽象操作)
              • 则需重新定义具体的实现细节

全部评论 (0)

还没有任何评论哟~