day_01《Think in Java》读书笔记(对象导论)
计算机革命起源于机器,因此,变成语言的产生也始于对机器的模仿。
1.1 抽象的过程
- 万物皆为对象(待求解问题任何的任何概念化构件,例如服务,狗,视为程序中的对象);
- 程序是对象的集合,它们通过发送消息来告知彼此所要做的(调用该对象的方法的消息或请求);
- 每个对象都有自己的由其他对象所构成的存储(例如jar包、接口、类,构建复杂体系的同时将复杂性隐藏在简单性背后);
- 每个对象都拥有其类型(对象是class的instance,class与“类型”同义,class之间的区别就是“可以接收什么样的消息”);
- 某一特定类型的所有对象都可以接收同样的消息(“男人”类型的对象也是“人”类型的对象,所以“男人”对象必定能够接收发送给“人”对象的消息。可通过编写与”人“交互并自动处理所有与人类性质相关的事务的代码。substitutability可替代性OOP重要概念之一)
对象具有状态(内部数据)、行为(方法)和标识(内存中的唯一地址,或者其他唯一的标识)
1.2 每个对象都有一个接口
创建抽象数据类型(类)是面向对象程序设计基本概念之一,抽象数据类型与内置类型几乎完全一致;
参照”银行出纳员问题“给出的解释:
-
每个类成员或元素都具有某种共性:每个账户有余额、每个出纳都可以处理存取款请求等;
-
每个成员都有其自身的状态:每个账户都有不同的余额、每个出纳都有自己的姓名;
因此出纳、账户等都在计算机程序中被表示成唯一的实体;(实体类pojo、domain)这些实体就是对象,每一个对象都属于定义了特性(状态)和行为(方法)的某个特定(标识)的类;
一个类实际上就是一个数据类型,程序员通过设计类来解决问题,而不止限于现有的用来表示机器中存储单元的数据类型;
面向对象程序设计的挑战之一:问题空间的元素和解空间的对象之间创建一对一的映射;怎样才能获取有用的对象?
答案就是必须有某种方式产生对对象的请求,使对象完成各种任务,每个对象都只能满足某些请求,这些请求由对象的接口(interface)定义,决定接口的便是类型;
接口决定了对某一特定对象所能发出的请求;程序中必须有满足这些请求的代码(接口只接受相对应请求,不会请求,所以编程时需要该接口的实现类来处理请求);
整个过程为:向某个对象”发送消息“(产生请求),这个对象便知道此消息的目的,然后执行对应的代码(该接口实现类中的方法);例如:
//创建一个灯对象
Light lt = new Light();
//通过"."对灯发送一个请求,接口中的off()方法就会被调用
lt.off();
1.3 每个对象都提供服务
当时图开发或理解一个程序执行时,最好的方法之一就是将对象想象为”服务提供者“;程序本身为用户提供服务,通过调用其他对象提供的服务来实现这一目的。
1.4 被隐藏的具体实现
类创建者:创建新数据类型的程序员(我理解为写类库)
客户端程序员:在其应用中使用数据类型的消费者(我理解为调用类库实现快速开发)
- 类创建者不希望注解的类库被修改,只把有用的服务展示出来方便客户端程序员调用:
- 类创建者可以改变类库内部工作方式,而不必担心影响到客户端程序员;
所要使用访问控制权限:
public:任何人都可用;
private:类创建者和类内部方法可用(类创建者和客户端程序员的一堵墙);
protected:同private,但是可以被继承的类访问;
默认访问权限也叫包访问权限:类可以访问同包(库构件)中的其他类的成员;
(感觉书里说的比较具体,但是那张表更加直观,并且已经熟记于心,建议初学者使用访问权限那张表)
1.5 复用具体实现
代码复用是面向对象程序设计语言的优点之一
最简单的复用就是直接使用该类的一个对象,或者将该类的对象置于某个新类中,“创建一个成员对象”。这个新的类,可以是由任意类型的其他对象以任意可以实现新的类中想要的功能的方式所组成。
使用现有的类合成新的类,称为“组合”(composition);若组合是动态发生,称为“聚合”(aggregation)。组合是一种“has-a”(拥有)关系;
新类的成员对象通常声明为private;
1.6 继承
以现有类为基础,复制它,然后通过添加和修改这个副本类来创建新类;当源类(基类、超类、父类)放生改变时,被修改的“副本”(导出类、继承类‘、子类)也会反映这些变动;
例如:
几何形为“父类”,三角形、圆形为“子类”;三角形复制了几何形的接口,此时三者具有相同的类型、行为;
通过继承而产生的类型等价性,是理解面向对象程序设计方法内涵的重要门槛;
- 直接在导出类中添加新方法;(同时在程序设计过程中需要考虑是否在基类中也添加方法)
为圆形添加一个“Π”; - 改变现有基类的方法的行为,称为“覆盖”(overriding),理解为使相同的接口方法,在新类中做不同的事情
处理三角形周长用 C=3*l,圆周长使用 C=2Πr
1.6.1 “是一个”与“像是一个”关系
- “是一个”:可以使用is-a来描述的关系,例如:“一个圆形是一个几何形·”,来判断是否继承;此时是存粹替代(替代规则);
- “像是一个”:导出类扩展接口元素之后,依然可以替代基类,但是基类不能访问新添加的方法,这样并不完美;此时描述为“is-like-a”;平时开发都是这种方式;
1.7 伴随多态的可互换对象
- [问题?多态是怎么实现的] 这一段落暂时读不通顺。但是我理解的多态,就是根据不同消息做出不同相应。比如方法中参数列表的不同或者是返回值的不同,它们都会做不同的事情,都可以理解为多态性;但是这一机制是如何实现的,还是不懂;
1.8 单根继承结构
除C++以外的所有OOP语言最终都继承自单一的基类(Java中的Object超类)
单继承结构保证所有对象都具备某些功能。所有对象可以更容易的在堆中创建,简化参数传递;方便垃圾回收;
1.9 容器
对于某些特定问题,集体需要多少对象、存活多久,如何存储?
- [ 解决方案] 创建一种新的对象类型,该对象类型持有对其他对象的引用;
例如容器,查阅很多资料后发现这是一个翻译问题,我们说的集合居然和Java中解释的集合不一样,容器这个词更为合适;
不同容器存在的原因:
1.不同类型容器提供不同类型接口和外部行为;
2.不同容器对于某些操作具有不同效率;
1.9.1 参数化类型
可以存储Object类型的容器可以存储任何类型,容易复用;
当对象引用置入Object容器时,需要向上转型为Object,因而取出的时候需要向下转型;
这时候面临的问题就是,向下转型的容错率极低;
- [解决方案 ] 针对具体对象创建容器,就是参数化类型机制,Java SE 5提出的泛型;
//创建存储几何体对象的ArryList容器:
ArryList<shap> shaps = new ArryList<shap>;
1.10 对象的创建和生命周期
使用对象时,最关键问题之一就是它们的生成和销毁方式
有些对象在本系统中举足轻重,但是在其它系统中,却不怎么起眼;当我们使用完这个对象的引用,其它系统可能正在使用该对象的另一个引用;何时销毁变得很复杂;
- [ 解决方案一 ] 编译时处理:C++在编写时将对象置于堆栈(静态存储区域)中;使用析构函数,明确要被销毁的对象何时销毁,也是我最喜欢的方式,条理清晰,一切都在控制之内,效率控制极佳,程序执行速度快;但是,不具有灵活性,程序员要知道对象数量、生命周期、和类型,不适用于一般化问题,容易内存泄露;
- [ 解决方案二 ] 运行时处理:在堆(heap)中的内存池中动态创建对象。当代码执行到那一刻才会知道需要多少对象、他们的生命周期如何、它们的具体类型。如果需要对象,就在堆中直接创建;Java完全采用动态分配内存方式,(new关键字);Java提供“垃圾回收器”机制,自动发现不被使用的对象并销毁,处理内存释放问题;
1.11 异常处理:处理错误
异常是一种对象,在错误点被“抛出”,被专门设计用来处理特定类型错误的一场处理器“捕获”。处理器和程序并行且,在错误发生的时候执行另一条路径。
异常不能忽略,提供了一种从错误状况进行可靠恢复的途经,加强程序的“鲁棒性”(健壮性);
1.12 并发编程
并发:把问题切分成多个可独立运行的部分(任务,线程),从而日高程序响应能力。
隐患:“共享资源”;
- [ 解决方案 ] 为资源加资源锁,当一个进程使用完后,在释放,其他进程可以继续使用;
1.13 Java与Internet
Java解决了在万维网(WWW)上的程序设计问题
1.13.1 Web是什么
1.客户/服务器计算技术
其核心思想:系统具有一个中央信息存储池,用来存储某种数据,它通常存在于数据库中,可以根据需要将它分发给某些人员或机器集群;
事务处理:保证客户新插入的数据不会覆盖另一个客户插入的数据;也不会再插入过程中丢失;
2.Web就是一台巨型服务器
对某个服务器产生一个请求,然后返回一个文件,客户机上的浏览器根据本地机器的格式解读文件;
1.13.2 客户端编程
1.插件
2.脚本语言
JavaScript
3.Java
安全、跨平台、国际化
4.备选方案
5. .NET和C#
6. Internet和Intranet
1.13.3 服务器编程
servlet