记录在6.031中发现的新东西
MIT6.031能带给我的:英语阅读材料,复习Java,为CS61C的学习做准备
Reading 1: Static Checking
Static typing
Java是静态类型语言,所有变量的类型在程序运行(编译)前都是已知的,也可以据此推断出相应表达式的类型,因而我们在编程的时候IDE就可以发现其中的问题。
Python是动态类型语言,程序运行时才知道变量的类型。
Python3.5及更新的版本,可以通过类型提示的方式在程序运行前进行类型检查:
# Python function declared with type hints
def hello(name:str)->str:
return 'Hi, ' + name
Array and List
Java(C/C++也是如此)中的Array一旦声明了,其长度就不能变化了。因而在运行的时候经常出现缓存溢出的情况,这也是很多网络安全漏洞/网络蠕虫的罪魁祸首。
在Java中,List只是一个接口,具体的实现有ArrayList/LinkedList。
List<Integer> list = new ArrayList<Integer>();
为什么这里泛型用的是Interger而不是int呢?因为List只能处理对象类型(object type),而不能处理基本类型(primitive type)。每一个基本类型都有一个与之对应的对象类型,例如:int/Integer, long/Long, float/Float, double/Double。
Method
以static修饰的方法不能作为实例方法所调用,只能使用类名来直接调用该方法。
Mutating values vs. reassigning variables
重要的设计原则—有目的禁止某些变量的值在运行时改变(变量在运行时超出预期的变化通常会导致程序出现bug);
使用final关键词来声明那些不会再重新赋值的变量。
Documenting assumptions
编程的时候有两个主要目标:
和计算机沟通。编写具有正确语法、逻辑的代码,通过编译器的执行得到正确结果;
和人沟通(这也是我经常忽略的方面)。通过编写详细的注释、简明易懂的代码,使得其他人(包括自己)能理解代码的逻辑,方便在以后对其进行改进,重用。
Reading 2: Basic Java
== vs. equals()
前者比较的是两个变量存储的bit是否相同(int、String、地址);
equals()默认和前者效果相同,但我们可以override它,使其表现出我们想要的效果(例如比较地址中存的值是否相等);
== 和 equals()相比要更加强势一点。
Reading 3: Testing
Choosing test cases by partitioning
通过将module的输入空间分区,在每个分区和边界中选择一个test案例来组成该module的测试单元。
太学术了,这一节用处不是很大。
Reading 4: Code Review
略。
Reading 5: Version Control
版本控制系统和git,略。
Reading 6: Specifications
在Java中,尽量避免null的使用。
Reading 7: Designing Specifications
略。
Reading 8: Mutability & Immutability
String和StringBuilder:在字符拼接的场景中,String每次拼接都会创建新的临时空间,StringBuilder则是在原来空间的基础上进行拼接的,性能更好。
Reading 9: Avoiding Debugging
静态类型检查、断言、尽量避免全局变量的使用有利于debug。
Reading 10: Abstract Data Types
抽象数据类型和封装的相关概念。
Reading 11: Abstraction Functions & Rep Invariants
略。
Reading 12: Defining ADTs with Interfaces, Generics, Enums, and Functions
一些Java基础,接口、子类、枚举、函数之类的。
Reading 13: Debugging
一些调试的方法,实际操作中意义不大,太书面了。
Reading 14: Recursion
递归的概念。
Reading 15: Equality
==和equal()。
Reading 16: Recursive Data Types
package-private: 不使用private/public声明的class/method,不能被当前package之外的方法看见/使用,强度介于public和private之间。
Reading 17: Regular Expressions & Grammars
正则表达式相关内容
最重要的三个操作符,重复、拼接和组合(maybe)。一般来说,使用这三个操作符基本可以匹配所有字符串。
除此之外,正则表达式中还有一些操作符,可以用来简化表达式,如?、+、{}、[]等(Link)。
?:字符出现0次/1次
+:出现至少一次
{}:范围
[]和[^]: 单个匹配
Reading 18: Parsers
略。
Reading 19: Writing a Program with Abstract Data Types
略。
Reading 20: Concurrency
并发的两大模型: 共享内存和 消息传递。
并发模型又可以分为两种不同类型,进程和线程。
进程:一个进程是一个正在运行程序的实例,并且和同一台主机上的其他进程相隔离,并不会共享内存,但消息传递是天然具有的。进程的抽象就是一个虚拟计算机,它让程序感觉自己在一台全新的主机上运行。
线程:抽象为一个虚拟处理器。它和进程中的其他线程一样,运行同一个程序,共享同一块内存空间。
Reading 21: Thread Safety
略。
Reading 22: Locks and Synchronization
互斥锁,在并发编程中使用它来维护线程安全,使得在任意时刻,最多只有一个线程访问共享内存空间。互斥锁有两种操作:
获取——获取共享内存空间的使用权。如果当前有线程正在使用的话,它会阻塞想要使用的线程,直到其他线程释放互斥锁。
释放——释放互斥锁,使共享内存空间可以被其他线程获取。
死锁(通常由阻塞产生):多个并发线程卡住,等待对方做出某种行为时,就会发生死锁。例如,两个进程A和B,同时访问银行账户C和D,想向对方转账的情形。此时进程A拥有账户C的锁,进程B拥有账户D的锁,但它们都得等待对方释放锁才能完成转账,两个进程都会被阻塞,进而形成死锁的局面。
Note:
同步——调用一旦开始,调用者必须等待方法执行完成,才能继续执行后续方法。
异步——方法一旦开始,立即返回,调用者无需等待其中方法执行完成,就可以继续执行后续方法。
Reading 23: Queues and Message-Passing
死锁更常见于有互斥锁的情形,但如果消息队列的容量是有限(很多消息传递系统出于性能的考量,都会使用固定容量的消息队列)的,当队列被消息填满的时候,就容易发生死锁的情况。
例如,在请求-响应模式中,A和B通过消息队列进行通信,如果A向B发送了过多的请求而没有及时处理B的响应,那么A的响应队列就将很快被填满,进而造成B阻塞。同时,A继续向B发送请求,使得B的请求队列被填满,进而造成A被阻塞,形成死锁。
Reading 24: Sockets & Networking
略。
Reading 25: Callbacks
first-class function,将函数像数据那样对待,作为参数传递/返回。
END
剩下的Reading用处不大,略。总结一下6.031吧,因为课程开始的时候安装软件失败了,再加上一些权限的原因,所以有很多coding的练习都没做,只阅读了官方给的这二十多篇阅读材料。课程总体上和CS61B的内容差不多,6.031更注重“合理”,课程一开始提出的关于coding的三个优秀特质始终贯穿全篇,并在这之间使用一些设计模式/理论对其进行具体的阐释。相比之下,CS61B更注重实践一点,课程资源的开放程度也更高。