第一章 对象导论

  • 1.1抽象过程

所有编程语言都提供抽象机制,人们所能够解决的问题的复杂性直接取决于抽象的类型和质量。
汇编语言是对底层机器语言的轻微抽象。
”命令式“语言(如C)是对汇编语言的抽象。
程序员必须建立起在机器模型(位于”解空间“内,这是你对问题建模的地方,例如计算机)和实际待解决问题的模型(位于”问题空间“内,这是问题存在的地方)之间的关联。
面向对象:将问题空间的元素以及其在解空间中的表示称为”对象“。这种思想的实质是:程序可以通过添加新类型的对象使自身使用与某个特定问题
OOP 允许根据问题来描述问题,而不是根据运行解决方案的计算机来描述问题。
对象:对象具有状态、行为、标识。意味着每个对象都可以拥有内部数据(他们给出了改对象的状态)和方法(它们产生的行为),并且每个对象都可以唯一地与其它对象区别开来,就是每一个对象在内存中都有一个唯一的地址。

  • 1.2 每个对象都有一个接口

面向对象程序设计的挑战之一,就是问题空间元素和解空间的对象之间建立一对一映射
每个对象都只能满足某些请求,这些请求由对象的接口(interface)定义,决定接口的便是类型。

  • 1.3 每个对象都提供服务

当正在试图开发或理解一个程序设计时,最好的方法之一就是将对象想象为”服务提供者“。程序本身将向用户提供服务,它将通过调用其他对象提供的服务来实现这一目的。你的目标就是去创建(或者最好是在现有代码库中寻找)能够提供理想服务来解决问题的一系列对象。
将对象看作是服务提供者还有一个附带好处是,它有助于提供对象的内聚性,避免在程序设计时将过多功能塞在一个对象中。

  • 1.4 被隐藏的具体实现

将程序开发人员按角色分为类创建者(哪些创建新数据类型的程序员)和客户端程序员(那些在应用中使用数据类型的类消费者)。客户端程序员的目标是收集各种用来快速应用开发的类,类创建者的目标是构建类,这种类只向客户端程序员暴露必需的部分,而隐藏其它部分。
访问控制第一个存在原因是让客户端程序员无法触及他们不该触及的部分
访问控制第二个存在的原因是允许库设计者改变内部的实现方式而不用担心会影响客户端程序员。
Java 用三个关键字在类的内部设定边界:public protected private
Protected 与 private 作用相当,差别是继承的类可以访问protected 但不能访问private
Java 还有一种默认的访问权限:包访问权限,在这种权限下,类可以访问在同一个包(库构件)中的其它类成员,但是在包之外这些成员如同指定了 private一样。

  • 1.5 复用具体实现

最简单地复用某个类的方式就是直接使用该类的一个对象,此外也可以将那个类的一个对象置于某个新的类中。我们称其为”创建一个成员对象“。新的类可以由任意数量、任意类型的其他对象以任意可以实现新的类中要想的功能方式所组成。因为是在使用现有的类合成新的类,所以这种概念被称为组合,如果组合是动态发生的,那么它通常被称为聚合。组合经常百视为”hase-a“(拥有)关系

  • 1.6继承

对象这种观念 使得你可以通过概念将数据和功能封装到一起,因此可以对问题空间的观念给出恰当的表示,而不用受制于必须使用底层机器语言。这些概念用关键字class来表示,它们形成了编程语言中的基本单位。
问题:在创建一个类之后,即使另一个新类与其具有相似的功能,你还得重新创建一个新类,如果我们能够以现有的类为基础,复制它,然后通过修改这个副本来创建新类那就好多了。
解决方式:通过继承便可以达到这样的效果,不过也有例外,当源类(被称为基类、超类或父类)发生变动时,被修改的”副本“(被称为导出类、继承类或子类)也会反映出这些变动
类型不仅仅只是描述了作用于一个对象集合上的约束条件,同时还有与其它类型直接的关系。两个类型可以有相同的特性和行为,但是其中一个类型可能比另一个含其它类型更多的特性,并且可以处理更多的消息(或以不同的方式来处理消息)。继承使用基本类型和导出类型的概念表示这种类型之间的相似性。
一个基类型包含其所有导出类型所共享的特性和行为,可以创建一个基本类型来表示系统中某些对象的核心概念,从基类型中导出其它类型,来表示此核心可以被实现的各种不同方式。
如果只是简单地继承一个类而不做其它任何事,那么在基类接口中的方法将会直接继承到导出类中,这意味着导出类的对象不仅与基类拥有相同的类型,而且还拥有相同的行为,这样做没有什么特别意义。
有两种方法可以使基类与导出类产生差异,第一种方法非常直接:直接在导出类中添加新方法,这些新方法并不是基类接口的一部分。
第二种也是更重要的一种使导出类和基类之间产生差异的方法是改变现有基类的方法的行为,这被称之为覆盖(overriding)那个方法

  • 1.6.1 ”是一个“与”像是一个“关系

继承只覆盖基类的方法(而不添加在基类中没有的新方法),意味着导出类和基类是完全相同的类型,因为它们具有完全相同的接口。结果可以用一个导出类对象完全替代一个基类对象。这可以被视为纯粹替代,通常称为替代原则。在某种意义上,这是一种处理继承的理想方式。我们将这种情况下的基类与导出类直接的关系称为”is-a“(是一个)关系
有时候必须在导出类型中添加新的接口元素,这样也就扩展了接口,这个新的类型仍然可以替代基类,但是这种替代并不完善,因为基类无法访问新添加的方法,这种情况我们称之为is-like-a(像是一个)关系。

  • 1.7 伴随多态的可互换对象

在处理类型的层次结构时,经常把一个对象不当作它所属的特定类型来对待,而是将其当作其基类的对象来对待。这使得人们可以编写出不依赖于特定类型的代码。
通过导出新的子类型而轻松扩展设计的能力是对改动进行封装的基本方式之一,这种能力可以极大地改善我们的设计,同事降低软件维护的代价。
在试图将导出类型的对象当作其泛化基类型对象看待时,仍然存在一个问题,当发送这样的消息时,程序员并不想知道哪一段代码将被执行,而对象会依据自身的具体类型来执行恰当的代码。
编译器不可能产生传统意义上的函数调用,一个非面向对象编程的编译器产生函数调用会引起所谓的前期绑定,这么做意味着编译器将产生对一个具体函数名字的调用,而运行时将这个调用解析到将要被执行的代码的绝对地址,然而在OOP中,程序直到运行时才能够确定代码的地址,所以当消息发送到一个泛化对象时,必须采用其他的机制。
为了解决这个问题,面向对象程序设计语言使用了后期绑定的概念。当向对象发送消息时,被调用的代码直到运行时才能确定。编译器确保被调用方法的存在,并对调用参数和返回值执行类型检查(无法提供此类保证的语言被称为是弱类型的),但是并不知道将被执行的确切代码
为了执行后期绑定,Java 使用一小段特殊的代码来替代绝对地址调用。这段代码使用在对象中存储的信息来计算方法体的地址
把将导出类看做是它的基类的过程称为向上转型(upcasting).转型(cast)这个名词的灵感来自于模型铸造的塑模动作;而向上(up)这个词来源于基础图的典型布局方式;通常基类在顶部,而导出类在其下部散开。因此,转型为一个基类就是在继承途中向上移动,即”向上转型“
多态才使得事情总是能够被正确处理,编译器和运行系统会处理相关的细节,你需要马上致电的只是事情会发生,更重要的是择优通过它来设计。

  • 1.8 单根继承结构

在Java中,所有的类最终都继承自单一的基类 Object,事实证明,单根继承结构带来了很多好处。
在单根继承结构中的所有对象都具有一个共同的接口,所以它们归根到底都是相同的基本类型。
单根继承结构保证所有对象都举报某些功能,所有对象都可以很容易地在堆上创建,而参数创建也得到了极大的简化。
单根继承结构使垃圾回收器的实现变得容易得多。由于所有对象都保证具有其它类型信息,因此不会因无法确定对象的类型而陷入僵局。
1.9 容器
这个通常被称为容器(也称集合,不过Java类库以不同的含义使用”集合“这个术语)的新对象,在任何需要时都可以扩充自己以容纳你置于其中的所有东西。因此不需要知道将来会把多少个对象置于容器中,只需要创建一个容器对象,然后让它处理所有细节。

从设计的观点来看,真正需要的只是一个可以被操作,从而解决问题的序列,对容器也有所选择,有两个原因,第一,不同容器提供了不同类型的接口和外部行为。
第二:不同的容器对于某些操作具有不同的效率。
最好的例子就是两只List的比较:ArrayList 和 LinkedList.它们都是具有相同接口和外部行为的简单序列。ArrayList中 随机访问元素是一个花费固定时间的操作,但是,对LinkedList来说,随机选取元素需要在列表中移动,这种待机是高昂的,越靠近表尾的元素,花费的时间越长。而另一方面,如果想在序列中插入一个元素。LinkedList的开销却要比ArrayList要小。

  • 1.9.1 参数化类型

创建这样的容器,它知道自己所保存的对象的类型,从而不需要向下转型以及消除犯错的可能,这种解决方案被称为参数化类型机制。参数化类型就是一个编译器可以自动定制作用于特定类型上的类。

  • 1.10 对象的创建和生命期

在使用对象时,最关键的问题之一便是它们的生成和销毁方式,每个对象为了生存都需要资源,尤其是内存。当我们不再需要一个对象时,它必须被清理掉,使其占有的资源可以被释放和重用。
Java完全采用了动态内存分配方式。每当想要创建新对象时,就要使用new关键字来构建此对象的动态实例。
Java 提供了被称为”垃圾回收器“的机制,它可以自动发现对象何时不再被使用,并继而销毁它。垃圾回收器提供了更高层的保障,可以避免暗藏的内存泄漏问题。

  • 1.11 异常处理:处理错误

异常是一种对象,它从出错地点被”抛出“,并被专门设计用来处理特定类型错误的相应的异常处理器“捕获”。异常处理就想是与城乡正常秩序路径并行的,在错误发生时秩序的另一条路径。
现在不再是只能退出程序,你可以经常进行校正,并恢复程序的执行,这些都有助于编写出更健壮的程序。

  • 1.12 并发编程

在计算机编程中有一个基本概念,就是在同一时刻处理多个任务的思想。把问题切分成多个可独立运行的部分(任务),从而提高程序的响应能力,在程序中,这些彼此独立运行的部分称之为线程,上述概念称为“并发”
通常,线程只是一种为单一处理器分配执行时间的手段,但是如果操作系统支持多处理器,那么每个任务都可以 被指派给不同的处理器,并且它们是在真正地并行执行。多线程所带来的的便利之一便是程序员不用再操心机器上是多个处理器还是只有一个处理器,由于程序在逻辑上被分为线程,所以如果机器拥有多个处理器,那么程序不需要特殊调整也能执行得很快。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。