algs4-1.1 基础编程模型

479 阅读5分钟

1. 原始数据类型与表达式

原始数据类型

  •  8 位整数,byte
  • 16 位整数,short
  • 32 位整数,int
  • 64 位整数,long
  • 16 位字符,char
  • 32 位单精度实数,float
  • 64 位双精度实数,double

表达式

  • Java 中使用 中缀 表达式,即:运算符在字面量或表达式之间。
  • 逻辑运算符中 ! 拥有最高优先级,之后是 &&,然后是 ||。

2. 语句

  • 声明语句:Java 是强类型语言,编译器会检查类型的一致性。
  • 赋值语句:左侧必须是单个变量,右侧是能够得到相应类型的任意表达式。
  • 条件语句:不同操作来处理不同的输入,分为 if 语句和 switch 语句。
  • 循环语句:主要是 while 语句和 for 语句,循环语句中的代码称为循环体。
  • 调用和返回语句:与静态方法有关,是执行流程和代码组织的另一种方式。
  • 其他语句
    • break 语句:退出循环。
    • continue 语句:立即开始下一轮循环。
    • return 语句:返回值。

3. 数组

  • 对于数组 a[],程序可以通过 a.length() 获取数组长度。

可能出现的异常

  • ArrayIndexOutOfBoundsException

数组别名

当我们将一个数组变量赋给另一个变量,那么两个变量都会指向同一个数组。

int[] a = new int[N];
a[i] = 123;
int[] b = a;
b[i] = 456;
System.out.print(a[i]); // 此处输出 a[i] 的值为 456

4. 静态方法

静态方法是一组在被调用时会被顺序执行的语句,拥有修饰符 static,区别于实例方法。

方法的性质

  • 方法的参数按值传递:方法中使用的参数变量可以引用调用者的数组并改变其内容,但不能改变与原数组变量本身(值传递)。也就是在方法中改变一个参数变量的值对调用者本身没有影响。
  • 方法名可以被重载:例如同名方法可以传入多种参数类型。
  • 方法只能返回一个值,但可以包含多个返回语句:返回被执行语句中第一条返回语句的参数。
  • 方法可以产生副作用:void 类型的静态方法会产生副作用(接受输入、产生输出、修改数组或改变系统状态)。

递归

方法可以调用自己; 递归代码比相应的非递归代码更加简洁优雅、易懂。

  • 最简单的情况:方法的第一条语句总是一个包含 return 的条件语句。
  • 递归的调用总是去尝试解决规模更小的子问题,这样递归才能收敛到最简单的情况。
  • 递归调用的父问题和尝试解决的子问题之间不应该有交集。
// 二分查找的递归实现

public static int rank(int key, int[] a) {
    return rank(key, a, 0, a.length - 1);
}

public static int rank(int key, int[] a, int lo, int hi) {
    // 如果 key 存在于 a[] 中,它的索引不会小于 lo 且不会大于 hi
    if (lo > hi) return -1;

    int mid = lo + (hi - lo) / 2;
    if (key < a[mid]) {
        return rank(key, a, lo, mid - 1);
    } else if (key > a[mid]) {
        return rank(key, a, mid + 1, hi);
    } else {
        return mid;
    }
}

基础编程模型

Java 开发的基本模是编写一个静态方法库(包含一个 main() 方法)来完成一个任务。

模块化编程

我们可以构造许多个静态方法库(模块),一个库中的静态方法也可以调用另一个库中定义的静态方法。这能够带来很多好处:

  • 程序整体的代码量很大时,每次处理的模块大小仍然适中;
  • 可以共享和重用代码而无需重新实现;
  • 很容易用改进的实现替换旧的实现;
  • 可以为解决编程问题建立合适的抽象模型;
  • 缩小测试范围。

单元测试

每一个静态方法库中都包含一个 main() 函数来测试库中的所有方法(有些编程语言不支持多个 main() 方法,所以不支持这种方式)。我们可以将 main() 方法作为一个开发用例,在开发过程中用它来测试更多的细节;也可以将它编写成一个测试用例来对所有代码进行一个全面的测试。当用例越来越复杂,我们可能会将它独立成一个模块。

外部库

  • 系统标准库 java.lang.*:包括实现了常用数学函数的 Math 库以及其他。
  • 导入的系统库,例如 java.util.Arrays:需要在程序的开头使用 import 语句导入。

5. API

模块化编程的一个重要组成部分就是记录库方法的用法并提供其他人参考的文档; 我们应该将自己编写的每一个程序都当作一个日后可以重用的库。 关于 API 的说明可参考 什么是 API ?


6. 输入输出

重定向与管道

重定向

将程序的输出重定向至一个文件:

% java RandomSeq 1000 100.0 200.0 > data.txt

重定向标准输入使从文件中读取数据:

% java Average < data.txt

管道

将一个程序的输出重定向为另一个程序的输入叫做管道:

% java RandomSeq 1000 100.0 200.0 | java Average

  • 突破了能够处理的输入输出流的限制
  • 运行的先后顺序由操作系统决定

7. 白名单过滤

信用卡公司的例子:

  • 将客户账号保存在一个文件中,称为白名单
  • 从标准输入中得到每笔交易的账号;
  • 使用测试用例在标准输出中打印所有与客户无关的账号,公司很可能拒绝此类交易。

% java BinarySearch tinyW.txt < tinyT.txt

此处的 tinyW.txt 就是一个白名单。


知识点+

  • Java 中一个静态方法不能作为另一个静态方法的参数,但在一些其他语言中可以。

习题

习题 1-1