4 Data Type and Type Checking
HIT软件构造的本章对应MIT软件构造阅读材料的第1章和第8章
第1章 静态检查 http://web.mit.edu/6.031/www/fa18/classes/01-static-checking/
第8章 可变性与不可变性 http://web.mit.edu/6.031/www/fa18/classes/08-immutability/
snapshot diagram必考,它属于(run time,code,moment)维度
目录
1 Data type in programming languages
2 Static vs. dynamic data type checking
4 Snapshot diagram as a code-level, run-time, and moment view
5 Complex data types: Arrays and Collections
1 Data type in programming languages
数据类型(type):值的集合,以及能在这些值上进行的操作
java分为两种数据类型:基本数据类型(primitive types)、对象数据类型(object types)
在Java中,基本数据类型的类型名是以小写字母开头的;而对象数据类型名以大写字母开头
java基本数据类型存在栈里(没有地址;java的栈的概念今年不讲),两个变量值相等则相等;对象有地址
选择题可能考这张表
2 Static vs. dynamic data type checking
静态类型语言:在编译时(运行前)就知道所有变量的类型,编译器也因此能推导出所有表达式的类型
动态类型语言:在运行时进行类型检查
类型检查:检测变量的值是否在数据类型定义的值的集合里,操作是否满足类型的要求
认为父类的值的集合包含子类的值的集合
静态类型检查:可在编译阶段发现错误,避免了将错误带入到运行阶段,可提高程序正确性、健壮性
动态类型检测是最强的,最严的,强于静态类型检查,能查出除数为0这种错误
Java是静态类型语言,Eclipse IDE在用户编写代码时就能进行静态类型检查(不需要等到编译);Java不进行动态类型检查
静态检查能检测出的错误:
在MIT软件构造的阅读材料中,只有static checking,没有static data type checking
static checking显然真包含static data type checking,像多了逗号这种错误显然不能算是类型错误
HIT在授课时特别强调静态检查中对类型的检查,甚至直接把static checking翻译为静态类型检查
动态检查能查出的错误:
当然,MIT阅读材料中所说的动态检查不仅仅是对类型的检查
静态检查保证每个变量里的值符合这个变量的类型,但它不知道变量的值确切是多少,故无法检测出像是int除0、数组下标越界这样的错误;而动态检查检能检测出这种与特定值相关的错误
注意,int类型除0不会有静态错误,会在运行时抛出异常,但double类型除0没有任何错误
以下是MIT阅读材料中的5个例子
Java会自动进行垃圾回收,发现一个对象没有指针指向时,就进行垃圾回收(本课程不涉及Java的垃圾回收)
3 Mutability and Immutability
mutable和immutable是针对对象而言的,immutable的对象已经创建就不能再改变
Immutable类:可以共享一个对象(比如说很容易传参数),而且安全;但是费内存
考法:判断某个给定的类是否是Immutable的;设计Immutable的类
final:引用的不变性(可能考判断题)
final字段需要在对象构造时初始化
不允许extends的类称为final类(声明时在class前加上final),final类中的所有方法自动称为final方法
String类是一个final类
这张图常考
不变性可以帮我们在编译阶段发现错误
小知识点
O(n^2)拷贝
s的第一个字符被复制了n次,第二个字符被复制了n-1次,依此类推。故时间复杂度是n^2。
可变类的两个优点:提高性能;程序的各部分间共享数据。
这题是MIT阅读材料上的一道练习
故传参的时候通常不传mutable类的参数
若一定要传,可以在传进去之后拷贝一下,然后使用拷贝得到的副本(防御式拷贝,defensive copy)(当然,使用immutable对象时不需要防御性拷贝)
在Java中每个方法都隐式得规定了不能改变输入的对象,除非显式地声明
故若在规约中(在后置条件中)没有提到会改变输入的对象,就说明不会改变这个对象
将mutable类改为immutable类需要这样做:将修改器方法改掉;不能将mutable类型的对象的引用作为返回值
以下是上面这张图的具体说明
全局变量是public static或者定义在类外面的public变量(包可见)
故groundhogAnswer不是全局变量;尽管它不是全局变量,但由于整个类都能访问它,函数startofSpring的规约的正确性就不仅仅依赖于这个函数
下面这题解释了“隐秘的bug”
注意,快速失败(fail fast)帮助用户快速找到bug
设计defensive copy经常考
在修改之前的代码中,可以通过非修改器方法对Period的属性值进行修改,这违背了信息隐藏的原则
4 Snapshot diagram as a code-level, run-time, and moment view
双线圈表示内存内容不可改变,单圈表示可以改
不可变的引用用双线箭头,可变的引用用单线箭头
snapshot也可以表示函数,函数用矩形表示,函数名写在左上角,局部变量写在右侧
5 Complex data types: Arrays and Collections
本节的重点在迭代器,考试时不会要求写具体的实现,但有可能要求写出iterator类的属性和方法
Java的for each循环使用迭代器实现的
使用迭代器对list操作时,不能使用list的remove操作(会抛出异常),应该使用迭代器的remove操作
list的remove会使list和迭代器的位置信息不一致
6 Useful immutable types
这节介绍了可变数据类型的不可变包装器
包装器可以增加/减少类的功能,在软件复用那一章会讲包装器的设计模式
这种包装器得到的结果是不可变的,但是这种“不可变”是在运行阶段获得的,编译阶段无法据此进行静态检查
通过listCopy不能改变list,但能直接通过list改变原本的ArrayList(绕过了copyList),考试经常会出这种小题
总结
本章重点是snapshot,immutable和mutable的区别