2018年1月7日15:45:58
前言
作为学习Java语言的经典之作《Java编程思想》,常常被人提起。虽然这本书出版十年有余,但是内容还是很给力的。很多人说这本书不是很适合初学者,我也是这么觉得(拙见),你最好熟悉一门高级语言,这样比较容易看懂。这本书也许不如国内一些教材那样,知识点精炼、简洁,但是大神Bruce Eckel更多讲的是Java编程思想,深入浅出。曾在某文章中看到过有人把这本书看过十遍,每看一遍都有不同的收获,希望多年后我也有这样的收获。
作为母校的教材(英文版),当我再次捧起这本书(中文版)的时候,我已不再是学生,以此系列文章记录自己的感悟与收获。
ps:英文原版《Thinking in Java》,在毕业的时候,以四毛一斤的高价卖给了收二手书的,想当初花了一百多人民币买回来,现在连尾数都收不回。
第一章 对象导论
总结:正如书上说的
本章将向读者介绍包括开发方法概述在内的OOP的基本概念。
本章介绍的是背景性的和补充性的材料。
第一章主要是叙述了面向对象的基本概念,和全书所讲述的内容的提纲,包括java语言三大特性:封装、继承、多态,容器,泛型,对象的生命周期,异常,并发,以及JavaWeb的相关知识。
1.1 抽象过程
所有编程语言都提供抽象机制。可以认为,人们能够解决的问题的复杂性直接取决于抽象的类型和质量。
编程语言的由来,其实和人类语言的由来一样的,抽象出来的啊。我说“苹果”,那个圆圆的、红红的、甜的东西就出现在你脑海中,你要说是青色的,你要说是iphone,那我也没办法。但是“苹果”就是从这些东西抽象出来的文字形式,它是从一个砸过牛顿的圆圆的、红红的、甜的东西抽象出来的。但是如果没有“苹果”这个词,我们是不是要说描述很长很长或者随身带一个“苹果”。计算机只认识0和1。
汇编语言是对底层机器的轻微抽象。接着出现的许多所谓“命令式”语言(如FORTAN、BASIC、C等)都是对汇编语言的抽象。
Java也是从底层语言抽象出来的,站在巨人的肩膀上。
面向对象的五个基本特性(Alan Kay总结):
1)万物皆为对象。
2)程序是对象的集合,它们通过发送消息来通知彼此所要做的。
3)每个对象都有自己的由其他对象所构成的存储。
4)每个对象都拥有其类型。
5)某一特定类型的所有对象都可以接收同样的消息。
Booch对对象提出了一个更加简洁的描述:
对象具有状态、行为和标识。
1.2 每个对象都有一个接口(interface)
接口确定了对某一特定对象所能发出的请求。但是,在程序中必须有满足这些请求的代码。这个代码与隐藏的数据以及构成了实现。
1.3 每个对象都提供服务
1.4 被隐藏的具体实现
访问控制(Access Control)的第一个存在原因就是让客户端程序员无法触及他们不应该触及的部分——这是部分对数据类型的内部操作来说是必需的,但并不是用户解决特定问题所需的接口的一部分。
访问控制的第二个存在原因就是允许库设计者可以改变类内部的工作方式而不用担心会影响到客户端程序员。
Java用三个关键字在类的内部设定边界:public、private、protected.
1.5 复用具体实现
最简单地复用某个类的方式就是直接使用该类的一个对象,此外也可以将那个类的一个对象置于某个新的类中。我们称其为“创建一个成员对象”。
因为是在使用现有的类,所以这种概念被称为组合(composition),如果组合是动态发生的,那么它通常被称为聚合(aggregation)。
组合经常被视为“has-a”(拥有)关系。
1.6 继承
1.7 “是一个(is-a)”与“像是一个(is-like-a)关系
如果子类继承父类,没有添加新的方法,是is-a关系。
如果子类继承父类,添加新的方法,是is-like-a关系。、
1.8 伴随着多态的可互换的对象
多态出现的原因:
在处理类型的层次结构时,经常想把一个对象不当作它所属的特定类型来对待,而是将其当作其基类的对象来对待。
实现多态意味着:
编译器不可能产生传统意义上的函数调用。
一个非面向对象的编译器产生的函数调用会引起所谓的前期绑定,意味着编译器将产生对一个具体函数名字的调用,而运行是将这个调用解析到将要被执行的代码的绝对地址。然而在OOP中,程序直到运行是才能够确定代码的地址。
为了解决这个问题,面向对象程序设计语言使用了后期绑定的概念。
为了执行后期绑定,Java使用一小段的代码来替代绝对地址调用。这段代码使用在对象中存储的信息来计算方法体。这样,根据这一小段代码的内容,每个对象都可以据用不同的行为表现。
在Java中,动态绑定是默认行为,不需要添加额外的关键字来实现多态。
1.8 单根继承结构
在Java中,所有的类最终都继承自单一的基类object。
好处:
在单根继承结构中的所有对象都具有一个共用接口,所以它们归根到底都是想同的基本类型。
单根继承结构保证所有对象都具备某些功能。
单根继承结构使垃圾回收器的实现变得容易得多。
1.9 容器
容器:
创建另一种对象类型。这种新的对象类型特有对其他对象的引用。
在Java中,具有满足不同需要的各种类型的容器:
List(用于存储序列), Map(也被成为关联数组, 用来建立对象之间的关联),set(每种对象类型只持有一个),以及以及租入队列、树、堆栈等更多的构件。
需要多种类型的容器的原因:
第一,不同的容器提供了不同类型的接口和外部行为。
第二,不同的容器对于某些操作具有不同的效率。
我们可以根据不同的需求选择不同的容器。面试的时候最多问到的问题之一应该有这个吧,关于ArrayList和LinkedList的区别。
在ArrayList中,随机访问元素是一个花费固定时间的操作;但是,对LinkedList来说,随机选取元素需要在列表中移动,这种代价是高昂的,访问越靠近表尾的元素,花费的时间越长。
而另一方面,如果想在序列中间插入一个元素,LinkedList的开销却比ArrayList要小。
知道它们的底层构造,理解起来就不是那难了,ArrayList存放对象的空间在物理上是连续的,底层是Array(数组),LinkedList存在对象的空间在物理上不一定是连续的。
这好比这里有一群孩子在操场上体育课,一开始孩子们要排队报个数,这样老师说3号孩子出来,就可以马上找到,这是随机访问元素。接着有一个孩子迟到了,然后这个孩子插入到队伍中,就需要挪一个位置给他,如果他在4号位置上,那么这样在4号后的孩子们都要挪。报完数就*活动了,这时候又来了一个迟到的孩子X,老师心情正好,因为男朋友说今晚一起去吃大餐,就不责备孩子X了,说去玩吧,这个孩子就插入在操场上玩耍的大部队里了。接着校长过来说要找X孩子,假设每个孩子只认识一个孩子,这样老师在操场边拉了一个孩子A说,我要找孩子X,孩子A只能告诉他认识的孩子B,继而B告诉C,如此循环,直到找到X,这就是随机访问元素。
这是个小故事,前者是ArrayList,后者是LinkedList。
1.9.1 参数化类型
在Java SE5出现之前,容器存储的对象都只具有Java中的通用类型:Object。
单根继承结构意味着所有东西都是Object类型,所以可以存储Object的容器可以存储任何东西。
把将派生类看做它的基类的过程称为向上转型。
向上转型成Object是安全的,如果从Object向下转型为具体类型,除非确切知道所要处理的对象的类型,否则向下转型是不安全的。
参数化类型机制的原因:要创建知道自己所保存的对象的类型的容器,不需要向下转型以及消除犯错误的可能。
在Java中,参数化类型称为泛型。
1.10 对象的创建和生命期
在使用对象时,最关键的问题之一便是它们的生成和销毁方式。
每个对象为了生存都需要资源,尤其是内存。
C++认为效率控制是最重要的议题:
为了追求最大的执行速度,对象的存储空间和声明周期可以在编写程序时确定,这可以通过将对象置于堆栈(它们有时被称为自动变量(automatic variable)或限域变量(scoped variable))或静态存储区来实现。
Java采用动态内存分配方式。
在称为堆(heap)的内存池中动态地创建对象。
因为存储空间是在运行是被动态管理的,所以需要大量的时间在堆中分配存储空间,可能要远远大于在堆栈中创建存储空间的时间。
动态方式有这样一个一般性的逻辑假设:对象趋向于变得复杂,所以查找和释放存储空间的开销不会对对象的创建造成重大冲击。
这里有一个翻译的坑,以前我不知道:堆栈是栈。
Java对象生命周期:
如果是在堆上创建对象,编译器就会对它的生命周期一无所知。
Java提供了被称为“垃圾回收器”的机制,它可以自动发现对象何时不再被使用,并继而销毁它。
开始于new,终结于GC。
垃圾回收器:
垃圾回收器提供了更高层的保障,可以避免暗藏的内存泄露问题。
Java垃圾回收器被设计用来处理内存释放问题(尽管它不包括清理对象的其他方面)。
垃圾回收器“知道”对象何时不再被使用,并自动释放对象占用的内存。这一点同所有对象都是继承自单根基类Object以及只能以一种方式创建对象(在堆上创建)这两个特性结合起来。
1.11 异常处理:处理错误
异常提供了一种从错误状况进行可靠恢复的途径。
1.12 并发编程
在计算机编程中有一个基本概念,就是在同一时刻处理多个任务的思想。
1.13 Java与Internet
JavaWeb相关叙述,略过。
1.14 总结
过程式语言:
数据定义和函数调用。
Java程序:
用来表示问题空间概念的对象(而不是有关计算机表示方式的相关内容),以及发送给这些对象的用来表示在此看空间内的行为的消息。
最后的最后,作者说,这章可以跳过。我?!