“我们没有意识到惯用语言的结构有多大的力量。可以毫不夸张地说,它通过语义反应机制奴役我们。语言表现出来并在无意识中给我们留下深刻印象的结构会自动投射到我们周围的世界。” -- Alfred Korzybski (1930)
面向对象编程是一种编程思维方式和编码架构
抽象
面向对象的程序设计程序员可利用一些工具表达“问题空间”内的元素这种表达非常具有普遍性,不必受限于特定类型的问题。我们将问题空间中的元素以及它们在解决方案空间的表示称作“对象”(Object)。一些在问题空间没有对应的对象体。通过添加新的对象类型,程序可进行灵活的调整,以便与特定的问题配合。
“纯粹”的面向对象程序设计方法
- 万物皆对象。
- 程序是一组对象,通过消息传递来告知彼此该做什么。
- 每个对象都有自己的存储空间,可容纳其他对象。
- 每个对象都有一种类型(class)。
- 同一类所有对象都能接收相同的消息。
接口
所有对象都是唯一的,但同时也是具有相同的特性和行为的对象所归属的类的一部分。
进行面向对象的程序设计时,面临的最大一项挑战是:如何在“问题空间”(问题实际存在的地方)的元素与“方案空间”(对实际问题进行建模的地方,如计算机)的元素之间建立理想的“一对一”的映射关系。
服务提供
最终目标是开发或调用工具库中已有的一些对象,提供理想的服务来解决问题。
将问题分解抽象成相应服务。软件设计的基本原则是高内聚:每个组件的内部作用明确,功能紧密相关。 在良好的面向对象设计中,每个对象功能单一且高效。可以提高我们代码的复用性,方便别人阅读和理解我们的代码。
封装
核心根本是“类的访问控制”,公开必要的内容,并隐藏内部实现的细节。可以有效地避免该工具类被错误的使用和更改,从而减少程序出错的可能。彼此职责划分清晰,相互协作。可以在不影响其他类调用的情况下,更新维护,封装使类相对独立。
Java 有三个显式关键字来设置类中的访问权限:public
(公开),private
(私有)和protected
(受保护)。这些访问修饰符决定了谁能使用它们修饰的方法、变量或类。
public
(公开)表示任何人都可以访问和使用该元素;private
(私有)除了类本身和类内部的方法,外界无法直接访问该元素。private
是类和调用者之间的屏障。任何试图访问私有成员的行为都会报编译时错误;protected
(受保护)类似于private
,区别是子类(下一节就会引入继承的概念)可以访问protected
的成员,但不能访问private
成员;default
(默认)如果你不使用前面的三者,默认就是default
访问权限。default
被称为包访问,因为该权限下的资源可以被同一包(库组件)中其他类的成员访问。
复用
一个类的对象作为另一个类的成员变量使用。新的类可以是由任意数量和任意类型的其他对象构成。
-
组合(Composition)经常用来表示“拥有”关系(has-a relationship)。例如,“汽车拥有引擎”。
-
聚合(Aggregation)动态的组合。
聚合关系中,整件不会拥有部件的生命周期,所以整件删除时,部件不会被删除,且多个整件可以共享同一个部件。
组合关系中,整件拥有部件的生命周期,所以整件删除时,部件一定会跟着删除。且多个整件不可以同时共享同一个部件。
两个类生命周期不同步,则是聚合关系,生命周期同步就是组合关系。
在新手程序员的印象里,或许先入为主地认为 “继承应当随处可见” 。沿着这种思路产生的程序设计通常拙劣又复杂。相反,在创建新类时首先要考虑“组合”,因为它更简单灵活,而且设计更加清晰。等我们有一些编程经验后,一旦需要用到继承,就会明显意识到这一点。
继承
利用现成的数据类型,对其进行“克隆”,再根据情况进行添加和修改,但继承并不完全等价于克隆。若原始类发生了变化,修改过的“克隆”类也会反映出这种变化。继承通过基类和派生类的概念来表达这种相似性。基类包含派生自它的类型之间共享的所有特征和行为。创建基类以表示思想的核心。从基类中派生出其他类型来表示实现该核心的不同方式。
从现有类型继承创建新类型。这种新类型不仅包含现有类型的所有成员(尽管私有成员被隐藏起来并且不可访问),而且更重要的是它复制了基类的接口。也就是说,基类对象接收的所有消息也能被派生类对象接收。根据类接收的消息,我们知道类的类型,因此派生类与基类是相同的类型。
区分派生类和基类的两种方法
-
在派生类中添加新方法
-
在派生类中覆写基类方法
"是一个"与"像是一个"的关系
如果派生类只覆写基类方法,因此它们具有相同的接口。一个派生类对象完全替代基类对象。这叫作"纯粹替代",也经常被称作"替代原则"。经常把这种基类和派生类的关系称为是一个(is-a)关系
如果派生类添加了新的接口元素,从而扩展接口。这种关系称为像是一个(is-like-a)关系。新类型不但拥有旧类型的接口,而且包含其他方法,所以不能说新旧类型完全相同。
多态
面向对象的程序设计语言是通过“动态绑定”的方式来实现对象的多态性的。编译器和运行时系统会负责对所有细节的控制;我们只需知道要做什么,以及如何利用多态性来更好地设计程序。
多态性是指具有不同功能的函数可以使用相同的函数名总而言之就是在不考虑对象的类型的情况下直接使用对象。
多态性的核心本质“方法”的
- 继承
- 重载
- 向上转型
将代码与具体类型分离,使代码可扩展。
单继承结构
单继承使所有对象都具有一个公共接口,同属于一个基类。
java采用多层继承取缔多重继承,使垃圾回收更加容易。
集合
“集合”这种类型的对象可以存储任意类型、数量的其他对象。它能根据需要自动扩容。
集合可以提供不同类型的接口和外部行为。堆栈、队列的应用场景和集合、列表不同,它们中的一种提供的解决方案可能比其他灵活得多。
不同的集合对某些操作有不同的效率。由于底层数据结构的不同,每种集合类型在执行相同的操作时会表现出效率上的差异。
对象创建与生命周期
Java 使用动态内存分配。每次创建对象时,使用 new
关键字构建该对象的动态实例,Java 的内存管理是建立在垃圾收集器上的,它能自动发现对象不再被使用并释放内存。
为了资源的重复利用,当对象不再被使用时,我们应该及时释放资源,清理内存。
对象的生命周期是指对象从创建到销毁的过程
异常处理
“异常”(Exception)是一个从出错点“抛出”(thrown)后能被特定类型的异常处理程序捕获(catch)的一个对象。