计算机是头脑延伸的工具,是一种不同类型的表达媒体。本文以背景性的和补充性的材料,介绍包括开发方法概述在内的面向对象程序设计(Object-oriented Programming,OOP)的基本概念。

本文通过概念+代码的方式,来帮助读者了解面向对象程序设计的全貌。

抽象过程

概念

机器模型:位于解空间内,是对问题建模的地方;可以这样理解,汇编语言和命令式语言,在解决问题时要基于计算机的架构;因此架构限定了解决方案,所以说机器模型是解空间。

实际待解决问题:问题空间,是问题存在的地方

如何抽象

抽象的类型和质量,决定了人们所能够解决的问题的复杂性。抽象的类型指的是“所抽象的是什么”。一种是在机器模型和实际待解决问题的模型之间建立联系的抽象;另一种是只针对待解决问题建模。而面向对象则是向程序员提供表示问题空间中元素的工具,我们将问题空间中的元素及其在解空间中的表示称为“对象”。

面向对象程序设计的特性:
  1. 万物皆是对象;
  2. 程序是对象的集合,对象间方法的调用是程序运行的基本表现;
  3. 对象可以包含其他对象;
  4. 每个对象都拥有其特定的类型;
  5. 某一特定类型的所有对象都可以接收同样的方法调用;

什么是对象?对象具有状态、行为和标识。每一个对象都可以拥有内部数据和方法,并且可以唯一的与其他对象区分开来

每个对象都应该都归属于一个类或接口

名词解释

对象:具有状态、行为和标识的实体。如银行存款账户是一个类,那么具体的每个人的银行存款账户就是这个类目下的对象。

类:可以看作类型来考虑。比如说鸟类,是动物中的其中一种类型。

类和对象

所有的对象都是唯一的,但同时具有相同的特性和行为的对象也都归属于某个特定的类。

类在Java中用关键词class表示。每个类的对象都具有某种共性和个性,如银行存款账户,每个账户中都有余额的属性,但每个账户中的余额又不同。在实际中,面向对象程序设计语言都用class关键字来表示数据类型,换而言之,每一个类都是一个数据类型。程序员可以自由地添加新的类(数据类型)来扩展编程语言,对实际问题进行处理。

对象的获取与方法调用

面向对象的挑战之一,就是在问题空间的元素和解空间的对象之间创建一对一的映射。

获取有用对象,必须以某种方式对对象进行请求,使对象完成各种任务。类型决定接口,而接口决定对象能满足的请求。就比如鸟类型,其提供的接口有飞翔,因此其能满足飞翔的请求。在接口确定了某一特定对象能够发出的请求后,接口的实现掌控着请求的具体行为的展现方式。在类型中,每一个可能的请求都有一个方法与之关联,当向对象发送请求时,与之关联的方法就会被调用。

以下代码是获取一个对象并调用其中的方法实例(你可以暂时不用理解,只需要知道形式即可,后面再反过来看就好)

public class Light {
//开灯
public void on() {
System.out.println("Light is on!");
}
//关灯
public void off() {
System.out.println("Light is off!");
} //这里是获取一个对象并调用其中方法的实例
public static void main(String [] args) {
//这里是核心代码,开灯操作
Light lt = new Light();
lt.on();
}
}

对象是服务提供者

程序通过调用其他对象提供的服务来向用户提供服务。程序员的目标就是去创建(或者最好是从现有的代码库中寻找)能够提供解决问题所需服务的一系列对象。

为什么要把对象看作是服务提供者呢?

  • 这是将问题分解为对象集合的一种合理方式。比如说,你正在创建一个簿记系统,那么,这个系统可以拆分为:我需要一个包括了预定义的簿记输入屏幕的对象、一个执行簿记计算的对象集合以及一个处理在不同的打印机上打印支票和开发票的对象。

  • 它有助于提高对象的内聚性。就像上面所定义的簿记系统,每个对象都可以很好地完成一项任务,但是它并不试图做更多的事情。职能太多,可能会导致对象的内聚性降低。简而言之,每个对象只做它该做的事。

程序访问权限控制

将程序开发人员按照角色划分为类创建者客户端程序员。类创建者创建新的数据类型,而客户端程序员在其应用中使用类创建者创建的新数据类型。如此一来,客户端程序员的主要目的就是收集各种用来实现快速应用开发的类;而类创建者的目的则是构建类,并向客户端程序员暴露必须的部分。

为什么类创建者需要对类的某些部分进行隐藏呢?或者说,为什么需要进行访问权限控制呢?

  • 让客户端程序员无法触及他们不该触及的部分,让客户端程序员分清楚,哪些东西对他们来说是必须的,哪些是可以忽略的。

  • 允许库设计者可以改变类内部的工作方式而不用担心会影响到客户端程序员。因为对客户端程序员所提供的那一部分可见的内容总是不变的,而库设计者改变的是其中隐藏的部分。

Java的访问权限控制关键字
修饰符 类内部 同包 子类 任何地方
private × × ×
× ×
protected ×
public
访问权限关键字的修饰范围
  • public:可以修饰外部类、属性、方法;
  • protected:只能修饰属性和方法;
  • private:只能修饰属性、方法、内部类;

复用具体实现

代码复用是面向对象程序设计语言所提供的最了不起的优点之一。

代码复用的基本方式:

  • 直接使用该类的一个对象;
  • 可以将某个类的一个对象置于一个新类中,作为新类的成员出现;

类之家的关系

关系是指事物之间存在单向或者相互的作用力或者影响力的状态。

在两个类之间存在有关系和没关系两种情况,在有关系的情况下,其关系包括以下六种类型

类关系 英文名 描述 强权方 UML图表示 示例说明
继承 extends 父类与子类之间的关系:is-a 父类 空心三角+实线,空心三角指向父类 鸟是动物
实现 implements 接口与实现类之间的关系:can-do 接口 空心三角+虚线,空心三角指向接口 鸟实现了飞翔的接口
组合 composition 比聚合更强的关系:contains-a 整体 实心菱形+实线,实心菱形指向整体 人类的头和身体是强组合关系
聚合 aggregation 暂时组装的关系:has-a 组装方 空心菱形+实线,空心菱形指向组装方 狗和牵狗的绳子是聚合关系
依赖 dependency 一个类依赖于另一个类:depends-a 被依赖方 箭头+虚线,箭头指向被依赖方 人喂小狗,小狗是喂这个动作的被依赖方
关联 association 类与类之间存在互相平等的使用关系:links-a 平等 实线 人与信用卡的关系,人用信用卡,信用卡可以读取个人信息

继承关系

以现有类为基础,复制它,然后通过添加和修改这个副本来创建新类。当源类发生变化时,被修改的副本也会反应出这种变动。生物学中对科目的定义,用于解释继承关系再恰当不过。

相关名词定义

父类:又称源类、基类、超类;

子类:又称导出类、继承类;

父类和子类

父类和子类之间的类型层次结构同时体现了他们之间的相似性和差异性。当继承现有类型时,也就创造了新的类型,同时子类又归属于父类的类型。这个新的类型不仅包括现有类型的所有成员,而且更重要的是它复制了父类的接口,这意味着所有对父类对象的调用同时可可以对子类对象发起,这遵循了编程原则之一的里氏替换原则。

如果只是简单地继承一个类而不做其他任何事情,那么在父类接口中的方法将会直接继承到子类中。当需要使父类和子类产生差异时,有以下两种方式:

  • 直接在子类中添加新的方法;在采用该种方案时需要仔细考虑是否存在父类也需要这些额外方法的可能性。
  • 覆写父类中的某个方法;该种方案需要在子类中定义与父类需覆写方法同名、同返回值类型、同方法参数类型的方法。

那么继承是否应该只覆写父类的方法呢?

如果继承只覆写了父类的方法,那么子类对象可以完全替代父类对象,这通常称之为替代原则,在这种情况下的类关系称为is-a;但有时又的确需要在子类中添加新的接口,这种情况下父类无法访问新添加的接口,这种情况下类关系为is-like-a,这时这种父类与子类之间的关系,被视为非存粹替代

多态

在处理类层次关系的时候,如果把任意一个特定类型的对象可以当作其基类对象来对待,就使得人们可以编写出不依赖于特定类型的代码。

相关概念

前期绑定:编译器将产生对一个具体函数名字的调用,而在运行时需要将这个调用解析到将要被执行的代码的绝对地址(意味着运行前就需要知道具体代码的位置)。

后期绑定:编译器只确保调用的方法存在,而且调用参数和返回值类型正确;在运行时,通过特殊代码,解析具体将要执行的代码的具体位置。

多态的实现理念

通过导出新的子类而轻松扩展设计的能力,是对改动进行封装的基本方式之一。

在试图将子类对象当作其基类对象来看待时,需要解决的一个问题是:编译器无法精确地了解哪一段代码将会被执行。在OOP程序设计中,程序直到运行时才能够确定代码的位置。

OOP程序设计语言使用了后期绑定的概念:编译器确保调用方法的存在,并对调用参数和返回值执行类型检查,但并不知道将被执行的确切代码。Java使用一小段特殊的代码来替代绝对地址调用,这段特殊代码用来计算方法体的具体位置。Java默认是动态绑定的。

向上转型

把子类对象看作父类对象的过程,称作向上转型。原因是在类图中,父类总是位于类图的顶部,把子类对象视为父类对象,即将子类类型向上推导。

单根继承

Java中所有的类最终都继承自单一的基类:Object

单根继承结构保证所有对象都具备某些功能。Object是任何类的默认父类,是在哲学方向上继续宁的延伸思考。

  1. 我是谁?getClass()说明本质上是谁,而toString()是当前类的名片。
  2. 我从哪里来?Object()构造方法是生产对象的基本方式;clone()是繁殖对象的另一种方式。
  3. 我到哪里去?finalize()方法说明了对象的最终归属
  4. 我是否是独一无二的?hashCode()和equals()就是判断与其他元素是否相同的一组方法。
  5. 与其他人如何协调?wait()和notify()方法是对象间通信和协作的一组方法。

容器

通常来说,如果不知道在解决某个特定问题时需要多少对象,或者他们将存活多久,那么就不可能知道如何存储这些对象。

在Java标准类库中提供了大量容器。不同的容器提供了不同类型的接口和外部行为,同时对某些操作具有不同的效率。如List中的ArrayList和LinkedList由于底层实现的不同,具备不同的应用场景。

参数化类型

由于容器只存储Object,所以将对象引入置入容器时,被向上转型为Object,在取出类型时会丢失其类型。在一定程度上可以使用向下转型的方式来获取其实际类型,但是这样做存在风险。

package a;

import java.util.*;

public class Container {
public static void main(String [] args) {
List list = new ArrayList();
list.add("Hello World!");
list.add(1);
//程序运行到这里是不会报错的,但是执行下面这一步的时候,就会出现异常了
for(Object o : list) {
//这一步会出现异常,因为List中存放的不仅仅是String类型,还有Integer类型,向下转型出现异常
String a = (String) o;
System.out.println(a);
}
}
}

那么用什么方式使容器记住这些对象究竟使什么类型呢?解决方案称为参数化类型,在Java中也称为泛型。表示方法为一对尖括号,中间包含类型信息。

List<String> list = new ArrayList<String>();

这样一来,就限定了List中只能存放String类型的对象啦!当然,我们还是能够通过反射绕过这层验证,毕竟在编译后运行时,是去泛型的。

对象的创建和生命周期

在使用对象时,最关键的问题之一便是他们的生成和销毁方式。

对象的创建

new Constructor();:通过new关键词向堆中申请内存,通过Constructor来说明类的创建方式。

生命周期

Java采用动态内存分配的方式。动态方式有个一般性假设:对象趋于变得复杂,所以查找和释放内存空间的开销不会对对象的创建造成重大冲击。动态方式所带来的更大的灵活性是解决一般化编程问题的要点。

Java提供了被称为垃圾收集器的机制,用来处理内存释放问题。垃圾收集器的运行基础是单根继承结构只能在堆上创建对象的特性。

异常处理

错误处理始终是编程的难题之一。

什么是异常

异常是一种对象,其从出错点被抛出,并被特定类型的异常处理器所捕获。异常处理就像与程序正常执行路径并行的、在错误发生时执行的另一条路径。

异常的处理

异常不能被忽略,它保证一定会在某处得到处理。异常提供了一种从错误状态进行可靠恢复的途径。Java一开始就内置了异常处理,并强制你必须使用它。它是唯一可接受的错误报告方式。

并发编程

在计算机编程中,存在着在同一时刻处理多个任务的思想。这些彼此独立运行的部分称为线程,同一时刻处理多个任务称为并发。

在单一处理器中,线程只是一种为单一处理器分配执行时间的手段,换而言之,如果只有一个处理器,那么多线程程序的运行不过是多个任务竞争使用处理器的性能。在多处理器的情况下,实现的才是真正意义上的并发,多处理器并行计算。

多线程同时存在一个隐患,在存在共享资源的时候,可能会造成资源之间的竞争,进而造成死锁。所以在多线程修改共享资源时,必然在共享资源使用期进行锁定。

在Java中,JDK1.5后提供了concurrent包支持更好的并发特性。

结语

以上是对象导论的一些基本概念,是继续阅读后面章节的非必要补充性材料。对于文中的一些代码段或概念,暂时不理解的,可以先放一放,等后面看完了,再回过来看就恍然大悟了。

下一节将讲解对象并写第一个Java程序。欢迎关注我的微信公众号,可以更方便的获取每日推送

《Java编程思想》读书笔记-对象导论的更多相关文章

  1. JAVA编程思想读书笔记(四)--对象的克隆

    接上篇JAVA编程思想读书笔记(三)--RTTI No1: 类的克隆 public class MyObject implements Cloneable { int i; public MyObje ...

  2. JAVA编程思想读书笔记(五)--多线程

    接上篇JAVA编程思想读书笔记(四)--对象的克隆 No1: daemon Thread(守护线程) 参考http://blog.csdn.net/pony_maggie/article/detail ...

  3. JAVA编程思想读书笔记(三)--RTTI

    接上篇JAVA编程思想读书笔记(二) 第十一章 运行期类型判定 No1: 对于作为程序一部分的每个类,它们都有一个Class对象.换言之,每次写一个新类时,同时也会创建一个Class对象(更恰当的说, ...

  4. JAVA编程思想读书笔记(二)--容器

    接上篇JAVA编程思想读书笔记(一) 第八章.对象的容纳 No1: java提供了四种类型的集合类:Vector(矢量).BitSet(位集).Stack(堆栈).Hashtable(散列表) No2 ...

  5. Java编程思想读书笔记(一)【对象导论】

    2018年1月7日15:45:58 前言 作为学习Java语言的经典之作<Java编程思想>,常常被人提起.虽然这本书出版十年有余,但是内容还是很给力的.很多人说这本书不是很适合初学者,我 ...

  6. Java编程思想读书笔记之内部类

    现在是够懒得了,放假的时候就想把这篇笔记写出来,一直拖到现在,最近在读<Java编程思想>,我想会做不止这一篇笔记,因为之前面试的时候总会问道一些内部类的问题,那这本书的笔记就从内部类开始 ...

  7. [Java编程思想] 第一章 对象导论

    第一章 对象导论 "我们之所以将自然界分解,组织成各种概念,并按其含义分类,主要是因为我们是整个口语交流社会共同遵守的协定的参与者,这个协定以语言的形式固定下来--除非赞成这个协定中规定的有 ...

  8. Java编程思想学习(一)----对象导论中多态的理解

    1.1抽象过程 1)万物皆对象. 2)程序是对象的集合,他们通过发送消息来告知彼此所要求做的. 3)每个对象都有自己的由其他对象所构成的存储. 4)每个对象都拥有其类型. 5)某一特定类型的所有对象都 ...

  9. <Java编程思想>读书笔记(1)-对象导论、一切都是对象

    1.面向对象编程:OOP (Object-oriented Programming) 2.Alan Kay 总结的面向对象语言5个基本特性: 1) 万物皆为对象 2) 程序是对象的集合,他们通过发送消 ...

  10. Java编程思想读书笔记(二)【一切都是对象】

    begin 2018年1月9日17:06:47 第二章 一切都是对象 Java语言假设我们只进行面向对象的程序设计. 2.1 用引用操纵对象 每种编程语言都有自己的操纵内存元素的方式 操纵内存元素的方 ...

随机推荐

  1. Shell egrep

    1.egrep是grep命令的扩展.grep使用需要脱义字符“\”.-E也可以满足. 2.正则参数. (). #任意一个任意字符. ()? #0或1个前面的字符. ()+ #1或多次的前面字符. () ...

  2. Git冲突和解决冲突-测试方法

    原文链接:https://www.cnblogs.com/blogslee/p/6828659.html

  3. 剑指offer(27)字符串的排列

    题目描述 输入一个字符串,按字典序打印出该字符串中字符的所有排列.例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba. 输入描述:输入 ...

  4. iOS开发 -------- AFNetworking实现简单的断点下载

    一 实现如下效果   二 实现代码 // // ViewController.m // AFNetworking实现断点下载 // // Created by lovestarfish on 15/1 ...

  5. C#方法过滤器

    方法过滤器 使用Emit和注解属性Attribute实现 使用方式 1. 自定义方法过滤器 可分别定义方法执行前过滤器, 方法执行结束过滤器, 方法异常过滤器 执行前过滤器继承 ExecutingFi ...

  6. 三层实现办公用品表CRUD(全过程)-ASP

    好久都没有写写技术博客了,自己最近几个月都要忙着搬家还有添置家当,所以一些博客就很少去写了,天道酬勤,有些吃饭的家伙还是不能有所懈怠,所以送上一个花了几小时给人事同事写的简单办公用品表的CRUD,希望 ...

  7. Java GC机制中Minor GC/Full GC

    Minor GC Young GC Full GC Major GC https://blog.csdn.net/chenleixing/article/details/46706039 内存划分为 ...

  8. postman(一):主界面模块解析

    在做接口测试时经常会用到postman,但是一直没有总结过,太过零散,这次找了一些好的资料,结合自己平时所用到的功能,总结一波 打开postman,主界面如下 左侧菜单 1.History标签 里面存 ...

  9. linux软件管理之源码包管理

    源码包管理tarball ====================================================================================tar ...

  10. js里面关于日期转换的问题

    我们拿到一个日期字符串:"2017-09-03",我们用new Date("2017-09-03")去转换成日期格式的时候,发现在火狐会报错,是因为火狐不支持这 ...