第三知识单元

面向对象程序设计

Java程序设计 第3讲,主讲人:李欣

Created: 2022-09-21 Wed 02:28

0.1. 互动课堂

Click to host the seminar.

0.2. 签到

https://xin.blue/tool/attendance/

0.3. 本次课的目标

  • 了解抽象和封装
  • 理解Java类的构成
  • 了解系统类库与自定义类
  • 了解继承
  • 了解多态

1. 抽象和封装

1.1. 抽象

抽象 是科学研究中经常使用的一种方法,即 去除 掉被研究对象中与主旨无关的 次要 部分, 或是暂时不予考虑的部分,而仅仅 抽取 出与研究工作有关的 实质 性的内容加以考察。

%%{init: { 'theme': 'forest', 'fontFamily': 'Times New Roman, KaiTi' }}%%
graph TB
    abstract["抽象"]
    abstract --- process["过程抽象"]
    abstract --- data["数据抽象"]

abstract.svg

Figure 1: 抽象的分类

1.2. 封装

封装 是指利用 抽象数据类型数据 和基于数据的
操作 封装在一起,数据被保护在 抽象数据类型的内部 , 系统的其他部分只有通过包裹在 数据 外面的 被授权操作 ,才能够与这个 抽象数据类型 交流交互

  1. 降低 复杂度提高 效率质量减少 错误保证 完整性
  2. 提高 可重用性

参考教材

  • 4.1.2 p.62

2. Java的类

2.1. 系统定义的类

Java® Platform, Standard Edition & Java Development Kit Version 18 API Specification

https://docs.oracle.com/en/java/javase/18/docs/api/index.html

Module java.base

https://docs.oracle.com/en/java/javase/18/docs/api/java.base/module-summary.html

Module java.desktop

https://docs.oracle.com/en/java/javase/18/docs/api/java.desktop/module-summary.html

2.2. 用户程序自定义类

[类的修饰字] class 类名称 [extends 父类名称][implements 接口名称列表] {
       变量定义及初始化语句
       方法定义及方法体
}
%%{init: { 'theme': 'forest', 'fontFamily': 'Times New Roman, KaiTi' }}%%
graph LR
    Class["类"]
    Class --- ClassHead["类头"]
    Class --- ClassBody["类体"]
    ClassBody --- Domain["域"]
    Domain --- Static["静态属性"]
    ClassBody --- Method["方法"]
    Method --- Behavior["类的行为"]
    Method --- Operation["操作"]

class.svg

Figure 2: 类的结构

2.3. 类的定义举例

class PhoneCard {
    long cardNumber; // 电话卡卡号
    private int password; // 电话卡密码
    double balance; // 电话卡余额
    String connectNumber; // 电话卡接入号码(预拨号码)
    boolean connected; // 电话是否接通
    boolean performConnection(long cn, int pw) { // 实现接入电话的操作
        if(cn == cardNumber && pw == password ) {
            connected = true;
            return true;
        }
        else {
            connected = false;
            return false;
        }
    }
    double getBalance() { // 检查电话是否接通,接通则返回当前余额
        if(connected)
            return balance;
        else
            return -1;
    }
    void performDial() { // 检查电话是否接通,接通则扣除本次话费
        if(connected)
            balance -= 0.5;
    }
}

2.4. 创建对象与定义构造函数

class PhoneCard { }

2.4.1. 创建对象

PhoneCard myCard = new PhoneCard();
类名 新建对象名 = new 构造函数();

参考教材

  • 4.2.3 pp.67-68

2.4.2. 构造函数

PhoneCard(long cn, int pw, double b,String s) {
    cardNumber = cn;
    password = pw;
    balance = b;
    connectNumber = s;
    connected = false;
}
  • 构造函数的 方法名类名 相同
  • 构造函数 没有 返回类型
  • 构造函数的主要作用是完成对 类对象初始化 工作
  • 构造函数一般 不能 由编程人员 显示地直接调用
  • 在创建一个类的新对象的同时,系统会 自动调用 该类的构造函数 为新对象初始化
class PhoneCard {
    long cardNumber; // 电话卡卡号
    private int password; // 电话卡密码
    double balance; // 电话卡余额
    String connectNumber; // 电话卡接入号码(预拨号码)
    boolean connected; // 电话是否接通
    PhoneCard(long cn, int pw, double b,String s) {
        cardNumber = cn;
        password = pw;
        balance = b;
        connectNumber = s;
        connected = false;
    }
    boolean performConnection(long cn, int pw) { // 实现接入电话的操作
        if(cn == cardNumber && pw == password ) {
            connected = true;
            return true;
        }
        else {
            connected = false;
            return false;
        }
    }
    double getBalance() { // 检查电话是否接通,接通则返回当前余额
        if(connected)
            return balance;
        else
            return -1;
    }
    void performDial() { // 检查电话是否接通,接通则扣除本次话费
        if(connected)
            balance -= 0.5;
    }
}
PhoneCard newCard  = new PhoneCard(12345678, 1234, 50.0, "300");
public class UsePhoneCard {
    public static void main(String args[]) {
        PhoneCard myCard = new PhoneCard(12345678, 1234, 50.0, "300");
        System.out.println(myCard.toString());
    }
}
class PhoneCard {
    long cardNumber; // 电话卡卡号
    private int password; // 电话卡密码
    double balance; // 电话卡余额
    String connectNumber; // 电话卡接入号码(预拨号码)
    boolean connected; // 电话是否接通
    PhoneCard(long cn, int pw, double b,String s) {
        cardNumber = cn;
        password = pw;
        if(b > 0)
            balance = b;
        else
            System.exit(1);
        connectNumber = s;
        connected = false;
    }
    boolean performConnection(long cn, int pw) { // 实现接入电话的操作
        if(cn == cardNumber && pw == password ) {
            connected = true;
            return true;
        }
        else {
            connected = false;
            return false;
        }
    }
    double getBalance() { // 检查电话是否接通,接通则返回当前余额
        if(connected)
            return balance;
        else
            return -1;
    }
    void performDial() { // 检查电话是否接通,接通则扣除本次话费
        if(connected)
            balance -= 0.5;
    }
    public String toString() {
        String s = "电话卡接入号码:" + connectNumber
            + "\n电话卡卡号:" + cardNumber
            + "\n电话卡密码:" + password
            + "\n电话卡余额:" + balance;
        if(connected)
            return (s + "\n电话已接通。");
        else
            return (s + "\n电话未接通。");
    }
}
电话卡接入号码:300
电话卡卡号:12345678
电话卡密码:1234
电话卡余额:50.0
电话未接通。

3. 继承与多态

3.1. 继承

参考教材

  • 5.1 pp.97-98
%%{init: { 'theme': 'forest', 'fontFamily': 'Times New Roman, KaiTi' }}%%
graph TB
    Card["电话卡"]
    Card --- CardWithoutNumber["无卡号电话卡"]
    Card --- CardWithNumber["有卡号电话卡"]
    CardWithoutNumber --- OriginalCard["电话磁卡"]
    CardWithoutNumber --- ICCard["电话IC卡"]
    CardWithNumber --- IPCard["IP卡"]
    CardWithNumber --- The200Card["200卡"]

phone-card-types.svg

Figure 3: 各种电话卡类及其间的继承关系

3.2. 多态

参考教材

  • 5.3.1 p.112
%%{init: { 'theme': 'forest', 'fontFamily': 'Times New Roman, KaiTi' }}%%
graph TB
    Polymorphism["多态"]
    Polymorphism --- ThroughOverload["方法覆盖实现的多态"]
    Polymorphism --- ThroughOverride["方法重载实现的多态"]
    Polymorphism --- ThroughReference["对象引用的多态"]

polymorphism.svg

Figure 4: 几种实现多态的方式