MIT_6.031之静态检查
MIT_6.031之静态检查
静态检查与动态检查
在编程语言中,静态检查和动态检查是两种不同的自动错误检测机制:
静态检查:编译器在程序运行之前检查代码中的错误。这些错误通常是语法错误、类型错误或违反语言规则的情况。例如,Java 是静态类型语言,类型不匹配的错误会在编译时被捕获。
动态检查:错误只有在程序运行时才会被检测到。这些错误通常是与程序逻辑或数据输入相关的。例如,数组越界、除以零等错误。
Java 的整数除法与数值陷阱
Java 中的数值类型有其独特的特性,可能导致一些新手常犯的错误。以下是一些常见的陷阱:
1. 整数除法截断
在 Java 中,整数除法并不会返回小数,而是直接舍去小数部分,返回一个 截断的整数。
1 | int result = 5 / 2; // result 的值是 2,而不是 2.5 |
原因:整数类型 (int
)
不支持分数,因此在进行除法操作时,任何小数部分都会被舍去。
2. 整数溢出
Java 中的 int
和 long
类型有固定的取值范围。int
的取值范围为 -2^31
到 2^31 - 1
,long
为 -2^63
到
2^63 - 1
。当结果超过这些范围时,就会发生整数溢出,并且不会抛出异常,而是返回错误的值。
1 | int big = 200000; |
Java 并不会静态或动态地捕获溢出,导致可能产生难以察觉的错误。
3. 浮点类型中的特殊值
Java 的浮点类型(如 double
)支持一些特殊的值:
- NaN (Not a Number):表示无法定义的数字结果,例如
0.0 / 0.0
。 - POSITIVE_INFINITY:表示正无穷大,例如
1.0 / 0.0
。 - NEGATIVE_INFINITY:表示负无穷大,例如
-1.0 / 0.0
。
1 | double result = 1.0 / 0.0; // result 为 POSITIVE_INFINITY |
某些操作(例如除以零或负数的平方根)会返回这些特殊值。
错误分析与练习
练习 1: 静态类型错误
1 | int n = 5; |
解释:if
语句的条件必须是布尔值
(boolean
),但 n
是 int
类型,这是一个
静态类型错误。编译器会报错,提示类型不匹配。
练习 2: 整数溢出
1 | int big = 200000; |
解释:这是整数溢出的例子。由于
int
的取值范围有限,结果超出了它的范围,溢出后的结果并没有被静态或动态捕获,导致错误答案。Java
的 int
类型最大值是 2147483647
,所以
200000 * 200000
导致溢出。
练习 3: 截断整数除法
1 | double probability = 1 / 5; // 结果为 0 而不是 0.2 |
解释:由于 1
和 5
都是整数,Java 会执行
整数除法,并将小数部分截断。因此,结果是
0
,而不是期望的
0.2
。正确的做法是至少将一个操作数转换为浮点数:
1 | double probability = 1.0 / 5; // 结果为 0.2 |
练习 4: 动态类型错误
1 | int sum = 0; |
解释:整数除以零在 Java 中会抛出
ArithmeticException
。虽然没有编译错误,但在运行时会出现异常,因为整数除法不允许除以零。
练习 5: 浮点数除以零
1 | double sum = 7; |
解释:虽然 double
除以零不会抛出异常,但结果是特殊值
POSITIVE_INFINITY
,因为除以零并不产生实数。Java
使用特殊值来处理这类情况。
数组和集合
1. 定长序列(数组)
1 | int[] a = new int[100]; // 创建一个长度为 100 的数组 |
数组在创建时是定长的,这意味着一旦创建,长度不能改变。数组越界(即访问不存在的索引)会在运行时抛出异常,例如
ArrayIndexOutOfBoundsException
。
2. 变长序列(集合)
1 | List<Integer> list = new ArrayList<>(); |
集合是动态的,可以随着元素的添加或移除而改变大小。与数组不同,Java 的集合类不会有静态的长度限制,但索引越界仍然会抛出运行时异常。
遍历与不变量
遍历元素时,可以使用 for-each
循环:
1 | int max = 0; |
使用 final
声明不变量
1 | public static List<Integer> hailstoneSequence(final int n) { |
在 Java 中,final
关键字可以用于声明常量或不变量,表明该变量一旦被初始化后就不能被修改。final
的使用有助于代码的可读性,并允许编译器进行静态检查,确保变量没有被不当修改。