第1章 如何深入高效地学习语言
在比较中学习多种语言时,一些知识能理解得更深刻。所谓语言不同,规则不同。
知道了语言设计者为解决何种问题而创造了这种语言,以及这种语言经历过怎么样的历史变迁后,慢慢地就能理解为什么需要有这种功能了。
了解了语言的历史,我们往往更能加深所学。
第2章 程序设计语言诞生史
优秀的程序员具有三大美德: 懒惰、急躁和傲慢(Laziness, Impatience and Hubris)。
“急躁”的意思是,程序员忍受不了程序执行的低效。
“傲慢”的意思是,程序员容不得对错误不管不顾。
“懒惰”的意思是,一项为了减少总能量支出,而不遗余力地努力的素质。
程序设计语言是为了给人们带来便捷,但是何为便捷,语言不同,便捷的含义也各不相同。
语言只是工具,要看通过使用它自己能做出多大成果,应当根据自己的实际情况选择好的工具。
第3章 语法的诞生
语言设计者制定的规则就是语法。
第4章 程序的流程控制
在提倡规则让读写程序更轻松的时代潮流中,结构化程序设计应运而生。
第5章 函数
函数,即把代码的一部分视作有机整体,然后切分出来并为之命名的程序设计机制。
把相同的操作封装在一起的好处不仅仅在于使程序更简短,也在于能使阅读程序的人无需反复读取相同内容的源代码。从冗长的程序中切分出反复使用的代码将其封装成一个整体,程序就更容易理解了。
第6章 错误处理
程序在执行过程中也有可能出错,出错时如何处理(错误处理)很重要。错误处理的方法大体可分为两种:使用返回值和使用异常(异常处理)。
为了提高软件的品质通过检查代码来确认程序员期待的程序行为,这一测评方法也是基于同样的想法。
发生错误应该停止操作立刻报告,这一设计思想被称为错误优先(fail first)。
第7章 名字和作用域
给内容或位置取个易于理解的名字,并用该名字来指示它们会更加方便。
作用域是编写易于理解的代码的有力工具,很多地方都应用了这一概念。
第8章 类型
类型是人们给数据附加的一种追加数据。
需要有表示这个值为何种类型的额外的信息,这就是类型。
第9章 容器和字符串
在不同的语言中,容器的名称不同,性质各异。
根据容器的使用目的、使用方式和操作类型的不同,最适宜的容器类型也会相应地变化。
这个地球不是单靠程序员运转的,现实中还有很多不依赖于程序实现方式的解决方案。
第10章 并发处理
为了实现便利的并发处理,出现了进程和线程的概念。
执行处理用的线路(CPU)只有一个,在人们察觉不到的极短间隔内交替进行多项处理,尽管在某一瞬间实际只进行一项处理,但人们会觉得似乎有多项处理在同时进行。
在合适的节点自发进行交替,利用这种方法实现的多任务(并发处理)称为协作式多任务模式。有一个问题,有可能某个处理一直找不到合适的节点进行任务切换从而持续地进行,导致其他处理无法等到执行的机会。
隔一定时间就进行交替,任务管理器在一定时间后强制中断现在正在进行的处理,以便允许其他程序执行。
并行执行的两个处理之间出现竞态条件必须同时满足以下三个条件。
- 两个处理共享变量
- 至少一个处理会对变量进行修改
- 一个处理未完成之前另一个处理有可能介入进来
人们在共享→非共享→共享、协调→非协调→协调、硬件→软件→硬件这样两种对立观念中左右摇摆,不单看片面而是兼顾两面,在平衡中灵活运用或许才是最为重要的。
第11章 对象与类
在不同语言中,同一个用语的含义可能会有很大差别。
在 C++ 语言里,类被定义为是“用户可自定义的类型”。
类的存在只不过是因为人们觉得有了它编写程序会更方便些,而约定的一种事项。
C++ 语言和 Java 语言的类具有以下几个作用:
- 整合体的生成器
- 可行操作的功能说明
- 代码再利用的单位
第12章 继承与代码再利用
继承的实现策略大体可以分为三种。
- 一般化与专门化
- 共享部分的提取
- 差异实现
一般化与专门化,在父类中实现那些一般化的功能,在子类中实现那些专门的个性化的功能
共享部分的提取,从多个类中提取出共享部分作为父类,子类并否为父类的一种。
差异实现,继承之后仅实现有变更的那些属性会带来效率的提高。它把继承作为实现方式再利用的途径,旨在使编程实现更加轻松。这些情况下通常子类都不是父类的一种。
使用方法多意味着继承这种机制有很高的自由度。
影响范围越广,就越难确定这种修改会不会带来什么问题。这个问题不是单靠在程序设计上下工夫就能解决的,同时也可以把大量的检查工作交给计算机去完成来帮助解决,这叫回归测试。
里氏置换原则可以表述为:假设对于 T 类型的对象 x,属性 q(x) 恒为真。如果 S 为 T 的派生类,那么 S 类型的对象 y 的属性 q(y) 也必须恒为真。
对于类 T 的对象一定成立的条件,对于类 T 的子类 S 的对象也必须成立。
当要继承某种类时,需要考虑该类是否可以被继承。
多重继承对于实现方式再利用是一种非常便利的方法。
类具有两种截然相反的作用。一种是用于创建实例的作用,它要求类是全面的、包含所有必需的内容的、大的类。另一种是作为再利用单元的作用,它要求类是按功能分的、没有多余内容的、小的类。
后记
只要是编程,大概都不可避免要产生一些错误(bug)。为了使程序准确运行,就需要调试(debug)。
我们很容易更加关注 How 的问题(即如何去实现),实际上,What(要实现什么)和 Why(为什么要实现)的问题也是不可忽略的。
专栏
要确认理解是否正确,首先得表达出来
为了验证理解正确与否,需要表达出来。只能基于自己的理解说出自己的观点,然后让第三方来判断和检验。
程序员一直受益于这一点。只有理解了这一点,才能和语言处理器打交道。
当你不知道该学习什么时
自己到底想做什么,然后再去学习能够达成这一目标的知识。
具体的知识和抽象的知识
我们不仅要学习具体的知识,更要有意识地去学习那些应用范围广泛的抽象的概念。
学习讲求细嚼慢咽
在庞大信息量面前心力交瘁的时候有三种战略可供参考:从需要的地方开始阅读,先掌握概要再阅读细节,从头开始逐章手抄。
从需要的地方开始阅读
明确阅读的目的并弄清楚为达成这一目的需要阅读哪些地方,就可以有针对性地阅读,无需在其他无关的地方花费大量精力。
先掌握概要再阅读细节
要先掌握概要再渐进式地追求细节,这是大的原则。
从头开始逐章手抄
当没有明确要做的事情或者想要了解的东西时,当简单浏览的内容过目即忘时,以这种学习状态,不管怎么学也无法获得真知。