面向对象程序设计先导Lec1

课程简介

  • 从java小白到一周内完成200行代码
  • 课程安排:八次课程 4次迭代作业

什么是面向对象

  • 面向对象是以对象为中心来构建程序逻辑的方法
    • 一切皆为对象
    • 程序逻辑:数据及其关系、行为及其关系
  • 使用这个概念来抽象描述 一个类可以以实例化出任意数量的对象
    • 类:数据与行为的综合逻辑体
    • 类关系:表征类之间的数据关系或行为关系

面向对象方法提供了控制程序复杂性的重要机制,提高程序的可读性和可维护性。

面向对象的三个复杂性控制机制

  • 封装 让类的内部复杂性外部不可见(黑盒子)方便使用者
    • 将数据与行为封装在一起,对外提供接口,隐藏类实现细节的机制
    • 累的使用者和实现者解耦
    • 接口与实现分离
  • 继承 通过建立类之间的抽象层次来协同降低复杂性
    • 找到共性,抽象得到类

    • 一个类从另一个类中获得属性和方法的机制

      • 建立了上下层关系:父类和子类
  • 多态 类通过提供多种形态方法来解耦复杂性
    • 针对同一个指令(方法名),一个类拥有多种功能形态
      • 不同的功能形态以参数区分
    • OO语言提供了根据对象和输入参数来匹配合适的方法(分派机制),解耦了类针对统一指令的多种情况

Java开发系统的构成

  • JDK Java开发工具包
    • Java编译器
    • Java解释器
    • Java类库
    • Java文档生成器
    • Java调试工具
  • JRE Java运行环境
    • Java解释器
    • Java类库

第一个Java程序

  • 类名称与相应程序文件名一致

Java程序的注释

  • 三种注释方式
    • 单行注释
    • 多行注释
    • 文档注释

Java程序的类型

  • 基础类型
    • 整数类型:int 4个字节 short 2个字节 long 8个字节 byte 1个字节

    biglnteger 16个字节(类)

    • 字符类型:char 2个字节
    • 浮点类型
      • float 32位
      • double 64位
    • 布尔类型
  • 构造类型:类、接口

Java程序的变量作用域

  • 变量作用域范围
    • 类级
    • 对象级
    • 方法级
    • 语句级

Java程序中的数组

  • 用以管理同类型的多组数据
  • 数据一旦声明,其容量不可变
  • 可以通过length来访问数组的规模
  • 数组本质上是一个对象指针,指向对象在1内存中的地址

Java程序的类

  • 编程单位,是Java程序的基本组成单位

在C中是函数

  • Java程序中的类由属性及方法组成
    • 属性定义数据结构
    • 方法定义对数据结构的操作函数
  • 每一个类都有一种构造方法,可用于实例化对象
    • 构造方法:初始化属性变量,返回对象指针

从结构化编程到面向对象编程

  • 结构化编程
    • 程序由函数组成
    • 函数由语句组成
    • 语句由表达式组成
  • 面向对象编程
    • 程序由类组成
    • 类由属性和方法组成
    • 属性和方法由语句组成
    • 语句由表达式组成
  • 结构化编程需要单独为结构体定义和实现相应的操作函数,当看到某个结构体类型,需要自己去找操作它的函数,而面向对象编程把结构体和操作函数封装在一起(形成类)
1
2
3
4
5
6
public class Person{
String name;
int age;
public void sayHello(){

}

Java程序中的接口

  • 接口是与类处于同一层次的类型
  • 把行为的设计和行为的实现分离

Java程序中接口的关系

Java程序中的访问权限设置

  • public、private
  • Java程序依据权限设置进行检查,如果违背则报错

Java程序中的static声明

  • 使用static关键字声明的属性和方法
    • 类级成员,否则为对象级成员
    • 类级成员在类加载时初始化,对象级成员在对象实例化时初始化
    • 类级成员在内存中只有一份,对象级成员在内存中有多份

Java程序中的this关键字

  • this关键字用于引用当前对象
  • 程序中的非静态方法可以使用this关键字
    • 指向当前类中的对象

Java程序中的object

  • object是一个类,是所有类的父类
  • object类中定义了几个方法
    • equals方法:按照对象的值进行比较
    • toString方法:将对象转换为字符串
    • hashCode方法:返回对象的哈希码
    • getClass方法:返回对象的类
    • notify方法:唤醒一个等待的线程
    • notifyAll方法:唤醒所有等待的线程
    • wait方法:使当前线程等待
    • finalize方法:在对象被垃圾回收前调用

Java语言如何学

  • Java语言中方法内的语句与C语言如出一辙
    • 没有C语言繁琐的指针及其运算
  • 理解前面所讲的关键概念

Java程序的错误

  • Java程序中的错误分为编译错误和运行错误
    • 编译错误:程序中存在语法错误,无法通过编译
    • 运行错误:程序中存在逻辑错误,无法正常运行
  • Java程序中的异常
    • 异常是程序中出现的错误
    • 异常分为受检异常和运行时异常

初学者常遇到的Java编译错误

  • …expected(缺少某些符号)
  • …cannot be resolved to a type(无法找到某个类型)
  • …cannot be resolved to a variable(无法找到某个变量)
  • …cannot be resolved to a method(无法找到某个方法)
  • …cannot find symbol(无法找到符号)
  • …illegal start of type(非法的类型开始)
  • …illegal start of expression(非法的表达式开始)
  • …incompatible types(不兼容的类型)
  • …missing return statement(缺少返回语句)
  • …missing method body(缺少方法体)
  • …missing semicolon(缺少分号)
  • …missing method body(缺少方法体)

常见的Java程序运行时错误

  • ArrayIndexOutOfBoundsException:数组下标越界
  • NullPointerException:空指针异常
  • NumberFormatException:数字格式异常
  • ArithmeticException:算术异常
  • ClassCastException:类型转换异常
  • IllegalArgumentException:非法参数异常
  • IndexOutOfBoundsException:索引越界异常
  • FileNotFoundException:文件未找到异常
  • IOException:输入输出异常
  • NoSuchMethodException:没有找到方法异常
  • NoSuchFieldException:没有找到字段异常
  • ClassNotFoundException:没有找到类异常
  • IllegalAccessException:非法访问异常

如何管理程序版本

开辟多个目录?如果你想恢复到几天前的某个版本?

  • 版本控制是指在软件开发过程中对程序代码、配置文件、文档等进行版本管理的一种方法,以便在软件开发过程中可以方便地回滚到之前的版本,或者查看不同版本的差异。
  • 程序开发会存在多个版本、存在多人协同开发

基于Git的版本控制

  • Git是一个开源的分布式版本控制系统,它允许开发者在本地对代码进行版本管理,同时也可以将代码提交到远程仓库,以便多人协同开发。
  • Git可以方便地查看不同版本的差异,可以方便地回滚到之前的版本,可以方便地多人协同开发。
  • Git是一个分布式版本控制系统,它允许开发者在本地对代码进行版本管理,同时也可以将代码提交到远程仓库,以便多人协同开发。

OO课程及先导课,项目代码提交在gitlab上,评测机主动从gitlab上拉取

Gitlab的四个区域

  • 工作区:本地开发环境,可以修改代码,提交到暂存区
  • 暂存区:临时存储修改的代码,可以提交到本地仓库
  • 本地仓库:存储本地的代码版本,可以提交到远程仓库
  • 远程仓库:存储远程的代码版本,可以拉取到本地仓库

Gitlab中的四种文件状态

  • 未跟踪文件;工作区中的新建文件,未添加到暂存区
  • 已修改文件;工作区中的文件被修改,未添加到暂存区
  • 已暂存文件;工作区中的文件被修改,已添加到暂存区,未添加到本地仓库
  • 已提交文件;工作区中的文件被修改,已添加到暂存区,已提交到本地仓库

Git中的操作

  • git init:初始化本地仓库
  • git add:将工作区中的文件添加到暂存区
  • git commit:将暂存区中的文件提交到本地仓库
  • git push:将本地仓库中的文件提交到远程仓库
  • git pull:将远程仓库中的文件拉取到本地仓库
  • git status:查看当前仓库的状态
  • git log:查看当前仓库的提交历史
  • git diff:查看当前仓库的修改差异
  • git reset:回滚到之前的版本
  • git checkout:切换到之前的版本
  • git branch:创建分支

Lec2:编写类与单元测试

本节大纲

  • Java程序的类
    • 构造方法
    • 查询方法
    • 修改方法
  • 对象引用与方法调用
    • 初步了解容器
  • Java程序的单元测试
    • Junit介绍
    • 编写Junit测试
    • 工具配置与使用

C语言与Java语言的比较

  • C语言: 面向过程,函数是编程的核心。
  • Java语言: 面向对象,类是编程的核心。
    • 协同方式不同:
      • C语言:函数调用 + 全局变量
      • Java语言:类调用 + 数据管理 + 抽象层次

类的定义

  • 类是一种自定义数据类型,包含数据和操作数据的方法。
    • 属性:数据管理
    • 方法:行为管理
  • 主类: 包含main方法的类,作为程序的入口。
  • 例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    public class Main {
    public static void main(String[] args) {
    Scanner scanner = new Scanner(System.in);
    System.out.print("Input your name: ");
    String name = scanner.nextLine();
    System.out.print("Input your age: ");
    int age = scanner.nextInt();
    System.out.printf("Hi, %s, you are %d\n", name, age);
    }
    }

类的属性和方法

  • 从需求中分析类的属性和行为:
    • 属性:管理什么数据
    • 方法:提供什么行为
  • 银行账户类(BankAccount)示例
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    public class BankAccount {
    private String name;
    private String ID;
    private int balance;

    public int getBalance() { return balance; }
    public String getAccountName() { return name; }

    public boolean withdraw(int amount) {
    if (amount > balance) return false;
    balance -= amount;
    return true;
    }

    public boolean deposit(int amount) {
    balance += amount;
    return true;
    }
    }

类的成员可见性

  • public:外部对象可访问
  • protected:本类和子类对象可访问
  • private:仅本类对象可访问

构造方法

  • 构造方法用于初始化对象属性。
  • Java默认提供无参数构造方法,用户定义构造方法后,默认方法失效。
  • 例子:
    1
    2
    3
    4
    public BankAccount(String name) {
    this.name = name;
    this.balance = 0;
    }

重载方法

  • Java允许同名方法,但参数列表必须不同(类型或数量)。
  • 方法重载
    1
    2
    3
    4
    5
    6
    7
    8
    public BankAccount(String id, int balance) {
    this.ID = id;
    this.balance = balance;
    }

    public BankAccount(String balanceStr) {
    this.balance = Integer.parseInt(balanceStr);
    }

对象引用与方法调用

  • 对象引用:类似于C语言的指针。
    • 确保对象引用的类型与实际对象类型一致。
  • 参数传递
    • Java中的对象引用是传递引用。
    • 例子
      1
      2
      3
      4
      5
      public static void swap(Point p) {
      int temp = p.x;
      p.x = p.y;
      p.y = temp;
      }

Java中的容器

  • ArrayList:动态数组,提供插入、检索、克隆和删除操作。
    • 例子
      1
      2
      3
      4
      ArrayList<Bottle> bottleArray = new ArrayList<>();
      for (Bottle b : bottleArray) {
      // 操作每个Bottle对象
      }

单元测试概述

  • 单元测试用于验证类的功能是否正确。
    • 静态测试:检查代码逻辑
    • 动态测试:运行代码并检查结果
  • Junit:Java单元测试框架,广泛使用。
    • 创建测试用例,设置断言,检查异常,建立测试流程。

编写Junit测试

  • 为每个类编写相应的测试类,测试类命名规则:类名 + Test
  • 测试方法通常与待测方法同名,并带有@Test标记。
  • 例子
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    import org.junit.Test;
    import static org.junit.Assert.*;

    public class BankAccountTest {
    private BankAccount ba = new BankAccount("1234567890");

    @Test
    public void deposit() {
    ba.deposit(50);
    assertEquals(50, ba.getBalance());
    }

    @Test
    public void withdraw() {
    ba.withdraw(50);
    assertEquals(0, ba.getBalance());
    }
    }

Junit基本功能

  1. 创建测试用例。
  2. 设置断言,检查返回值是否符合预期。
  3. 检查异常,验证方法是否抛出预期异常。
  4. 建立测试流程,使用@Before@After管理测试前后的操作。

在IDEA中使用Junit

  1. 安装Junit插件(一般内置)。
  2. 创建测试文件夹,保存单元测试文件。
  3. 使用快捷键创建单元测试类,选择要测试的函数。
  4. 补全测试代码,运行测试,查看覆盖率。
  5. 添加分支覆盖率,确保所有条件都被测试。

课程组提供了在IDEA中Junit测试使用说明,如果要在VSCode中使用Junit,可以参考这篇CSDN文章

覆盖率指标

  • 函数覆盖率:执行了多少方法
  • 语句覆盖率:执行了多少语句
  • 分支覆盖率:控制结构的分支是否被测试
  • 条件覆盖率:布尔表达式的真假分支被覆盖情况
  • 行覆盖率:有多少行被测试过