第一章 对象导论
1.1 抽象过程
面向对象程序设计方式:
1. 万物皆对象
2. 程序是对象的集合,他们通过发送消息来告知彼此所有做的
3. 每个对象都有自己的有其他对象所构成的存储
4. 每个对象都拥有其类型
5. 某一特定类型的所有对象都可以接受同样消息
简洁描述:对象具有状态、行为和标识。
1.2 每个对象都有一个接口
1、在类型中,每一个可能的请求都有一个方法与之相关联,当向对象发送请求时,与之相关联的方法就会被调用
1.3 每个对象都提供服务
将对象想象为“服务提供者”
1.4 被隐藏的具体实现
- 类创建者:构建类,只向客户端程序员提供必须的部分,而隐藏其他部分;
- 客户端程序员:只能访问类暴露的部分。
访问控制:
访问修饰符 | 本类| 同包 |子类 |其他|
private | √ | x | x | x|
默认 |√ | √ | x |x|
protected|√ |√ |√ |x|
public |√ |√ |√ |√ |
1.5 复用具体实现
最简单的服用某个类的方式就是直接使用该类的一个对象,还有就是可以将那个类的一个对象置于某个新的类中。
//直接使用
User user = new User();
user....
//新的类中的成员
public class Student{
String name;
User user;
}
1.6 继承
类与基类具有相同的类型:所有可以发送给基类对象的消息同时也可以发送给派生类对象。
使基类与派生类产生差异的两种方法:
1. 直接在派生类中添加新方法
2. 方法覆盖,改变派生类中继承基类现有方法的行为。
1.7 伴随多态的可互换对象
编译器确保被调用的方法的存在,并对调用参数和返回值执行类型检查(无法提供此类保证的语言被称为弱语言),但是并不知道将被执行的确切代码。
当向对象发送消息时,被调用的代码直到运行时才能确定。
Java中动态绑定是默认行为,不需要添加额外关键字来实现。(C++使用virtual关键字)
void doSomething(Shape shape){
shape.draw();
....
}
//调用doSomething
Circle circle = new Circle();
Square square = new Square();
doSomething(circle);
doSomething(square);
1.8 单根继承结构
Java中,所有的类最终都继承自单一的基类-Object类。
单根继承结构保证所有的对象都具备某些功能。例如垃圾回收器的实现就因为单根继承结构而变得容易很多。不会因为无法确定对象的类型二陷入僵局。
1.9 容器
容器,可以在任何需要的时候扩充自己来容纳置于其中的所有东西。不需要知道将来会把多少个对象放到容器中,只需要创建一个容器对象,然后让它处理所有细节就可以了。
容器有多种类别,例如List,Map,Set,以及队列,堆栈,树等,优点是:
1 不同容器提供了不同类型的接口和外部行为
2 不同的容器对于某些操作具有不同的效率,例如ArrayList 和 LinkedList
1.9.1 参数化转型
向上转型: 向继承结构的上层转型为一个更泛化的类型,是安全的。
向下转型: 向继承结构的下层转型为一个更具体的类型,是不安全的(除非确切知道要处理的对象类型)。
Java SE5 之前,容器存储的对象都只具有Java中的通用类型:Object。
Java SE5 开始,增加了参数话类型,也就是范型。使用一对尖括号包含类型信息来实现
ArrayList<Shape> shapes = new ArrayList<Shape>();
1.10 对象的创建和生命周期
在使用对象时,最关键的问题之一就是他们的生成和销毁方式。
创建和保存对象的方式:
1 对象的存储空间和生命周期可以在编写程序时确定,这样就可以将对象置于栈或静态存储区域来实现。优点是效率高,但是灵活性差,需要在编写时知道对象确切的数量、生命周期和类型。
2 在堆(heap)中的内存池中动态的创建对象。直到运行时,才知道对象的数量、生命周期和具体类型。优点是灵活性强,但是效率较差,需要大量的时间在堆中分配存储空间。
动态方式建立在一个逻辑假设:对象趋向于变得很复杂,所以查找和释放存储空间的开销不会对对象的创建造成重大冲击。
Java 完全采用了动态内存分配方式。每当想要创建新对象时,就要使用new 关键字来构建此对象的动态实例。
生命周期:
1 在栈中创建的对象:编译器可以知道对象存活时间,可以自动销毁它。
2 在堆中创建的对象:编译器对它的生命周期一无所知。需要通过编程方式来确定何时销毁对象,如果处理不好可能会导致内存泄漏。
Java 垃圾回收器被设计用来处理内存释放问题。可以知道对象何时不再被使用并自动释放对象占用的内存。
Java 编程比C++简单的原因:
1、所有对象都是继承自单根基类Object
2、只能以一种方式类创建对象(在堆中创建)
3、垃圾回收器
1.11 异常处理:处理错误
异常处理是编程的最困难问题之一。
异常是一种对象,它从出错点被抛出,并被专门设计用来处理特定类型错误的相应的异常处理器捕获。
异常不能忽略,它保证一定会在某处得到处理。
异常提供了一种从错误状况进行可靠恢复的途径。出现异常后,不再是只能退出程序,而是可以进行校正,并恢复程序的运行,有助于编写更健壮的程序。
Java 一开始就内置了异常处理,而且强制你必须使用它。这是唯一可接受的错误报告方式。
1.12 并发编程
并发:同一个时刻处理多个任务
普通并发实现:程序停下正在做的工作,转而处理某个其他问题,然后再返回主进程。(可以利用系统中断程序来实现,但是费时费力)
并发:线程彼此独立运行
优点:执行效率更高
隐患:资源共享
正常流程:某个任务锁定某项资源,完成任务后,释放资源,使其他任务可以使用这项资源。
1.13 Java与Internet
1.13.1 Web
- 客户/服务器计算技术 核心思想:系统具有一个中央信息存储池,用来存储某种数据,通常是存在数据库中。可以根据需要将它分发给某些人员或机器。
web 就是一台巨型服务器:所有客户机和服务器都同时存在与同一个网络中。
web浏览器:6一段信息不经修改就可以在任意型号的计算机上显示。
1.13.2 客户端编程
最初的Web“服务器-浏览器”设计是为了能够提供交互性的内容,但是其交互性完全由服务器提供。缺点是出错时,需要服务器返回通知,然后再回退重试。这样太慢且不优雅。
1. 插件:程序员可以下载一段代码,并将其插入到浏览器中适当的位置,以此来为浏览器添加新功能。
2. 脚本语言:将客户端的源代码直接嵌入html页面,解释这种语言的插件在html页面被显示时自动激活。缺点是代码会暴露给任何人。 JavaScript等客户端编程语言可以解决客户端80%的问题
3. Java ,解决剩下的20%问题。 Java 通过applet以及使用Java Web Start来进行客户端编程。applet是在web浏览器中运行的小程序。由于JRE的要求,Java applet没有大规模使用
4. 备选方案 Flex,ActionScript
5. .NET和C# Java的竞争者
6. Internet和Intranet企业内部网
1.13.3 服务器断编程
服务器编程的主要任务是接受前端请求后,需要去操作数据库来处理,并将最终结果返回。
可以使用Perl,Python、C++或其他语言来编写。Java是编写servlet及其衍生的JSP来实现