1.1 抽象过程
人们所能解决的问题的复杂性直接取决于抽象的类型和质量。
Java语言的五个基本特征:
1、万物皆为对象。
2、程序是对象的集合,它们通过发送消息来告知彼此所要做的。
3、每个对象都有自己的由其他对象所构成的存储。
4、每个对象都拥有类型。
5、某一特定类型的所有对象都可以接收同样的消息。
1.2 每个对象都有一个接口
创建抽象数据类是面向对象程序设计的基本概念之一。
类描述了具有相同特性(数据元素)和行为(功能)的对象集合,一个类实际上就是一个数据类型。
1.3 每个对象都提供服务
当正在试图开发或理解一个程序设计时,最好的方法之一就是将对象想象为“服务提供者”。程序本身向用户提供服务,它将通过调用其他对象提供的服务来实现这一目的。你的目标就是去创建(或者是去现有代码库中寻找)能够提供理想的服务来解决问题的一系列对象。
将对象看作服务提供者,有助于提高对象的内聚性。
1.4 被隐藏的具体实现
将程序开发人员按照角色分为
类创建者(创建新的数据类型的程序员)和
客户端程序员(在其应用中使用数据类型的类消费者)。
类的部分内容被隐藏,是用访问控制进行实现的。
访问控制的第一个存在原因是:让客户端程序员无法触及他们不应该触及的部分。
访问控制的第二个存在原因是:允许库设计者可以改变类内部的工作方式而不用担心会影响到客户端程序员。
访问指定词(sccess specifier)
public:表示紧随其后的元素对任何人都是可用的,
private:修饰的关键字表示出类型创建者和类型内部方法之外的任何人都不能访问的元素
protect:与private作用相当,差别仅在于继承的类可以访问protected成员,但是不能访问private成员
默认值(default):包访问权限,类可以访问在同一个包下的其他类的成员,但是在包之外,这些成员如同指定了private一样。
1.5 复用的具体实现
代码复用是面向对象程序设计语言所提供的最了不起的有点之一。
最简单的复用一个类的方式就是直接使用这个类的一个对象。此外也可以直接将那个累得一个对象直接置入某个新的类中。多个这样的操作被称为
组合。
如果组合是动态发生的,那么它通常被称为
聚合。组合经常被视为
“has a”(拥有)关系。
组合带来了极大的灵活性。
1.6 继承:复用接口
在创建了一个类之后,即使另一个新类与其具有相似的功能,你还是得重新创建一个新类。如果我们能够以现有的类为基础,复制它,然后通过添加和修个这个副本来创建新类那就要好多了。通过
继承便可以达到这样的效果,不过也有例外,当源类(基类、父类、超类)发生变动时,被修改的“副本”(导出类、继承类、子类)也会反映出这些变动。
类型不仅仅只是描述了作用于一个对象集合上的约束条件,同事还有与其他类型之间的关系。一个
基类型(子类)包含其所有
导出类型(父类)所共享的特性和行为。
父类和子类具有相同的类型。通过继承而产生的类型等价性是理解面向对象程序设计方法内涵的重要门槛。
两种方法可以使子类和父类产生差异:
1、直接在子类中添加新的方法。
is-a
2、改变现有父类 的方法行为,这被称为
覆盖(overriding) is-like-a
1.7 伴随多态的可互换对象
通过导出新的子类型而轻松扩展设计的能力是对改动进行封装的基本方式之一。
Java中,动态绑定是缺省行为,不需要添加额外的关键字来实现多态。
class Shape{
public void erase(){};
public void draw(){};
}
class Circle extends Shape {
public void erase(){
System.out.println("cir erase");
}
public void draw(){
System.out.println("cir draw");
}
}
class Triangle extends Shape {
public void erase(){
System.out.println("tri erase");
}
public void draw(){
System.out.println("tri draw");
}
}
class Line extends Shape {
public void erase(){
System.out.println("line erase");
}
public void draw(){
System.out.println("line draw");
}
}
public class Test{
public static void doStuff(Shape s){
s.erase();
// ...
s.draw();
}
public static void main(String[] args) {
Circle c = new Circle();
Triangle t = new Triangle();
Line l = new Line();
doStuff(c);
doStuff(t);
doStuff(l);
}
}
/*
Output:
cir erase
cir draw
tri erase
tri draw
line erase
line draw
*/
正因为多态才使得事情总是能够被正确处理。编译器和运行系统会处理相关的细节,你需要马上知道的只是事情会发生,更重要的是怎样通过它来设计。当想一个对象发送消息时
抽象基类和接口
通常在一个设计中,你会希望一个基类仅仅表示其导出类的借口,也就是说,你不希望任何人创建基类的实际对象,而只是希望他们将对象向上转型到基类,所以它的接口就派上用场。这是通过使用abstract关键字把类标识成抽象类来实现的。如果有人创建一个abstract的对象,编译器就会加以阻止,也可以使用abstract关键字来描述尚未被实现的方法,就像一个存根,表示“这是一个自此类继承来的所有类型都是具有接口的方法,但是此刻还没有为它设计任何具体实现”。抽象方法只能在抽象类内部创建,该类被继承时,抽象方法必须被实现,否则抽象类仍然是一个抽象类。
interface关键字比抽象类的概念更进了一步,他压根不允许有任何方法定义。接口是一个非常方便而通用的工具,因为它提供了接口与实现的完美分离。此外,只要愿意,就可以将多个接口组合到一起,而要从多个普通类或抽象类中继承却是不可能的。
1.8 对象的创建、使用和生命期
对象最重要的要素之一便是它们的生成和销毁。
对象的创建方式:
方式一: 给予程序员选择的权利。为了追求最大的执行速度,对象的储存空间和生命周期可以再编写成学时确定,这可以通过将对象置于堆栈(自动变量automatic variable)或限域变量(scoped variable)或静态存储区域内来实现。
方式二:是在被称为堆(heap)的内存池中动态地创建对象。
Java完全采用了第二种方式。每当想要创建新对象时,就要使用new关键字来构建此对象的动态实例。
对于允许在堆栈上创建对象的语言,编译器可以确定对象存活的时间,并可以自动销毁它。然而,如果是在堆上创建对象,编译器就会对它的生命周期一无所知。在像C++这样的语言中,必须通过编程方式来确定何时销毁对象,这可能会因为不能正确处理而导致内存泄露。Java提供了被称为“
垃圾回收器”的机制,他可以自动发现对象何时不再被使用,并继而销毁它。垃圾回收器非常有用,因为它减少了所必须考虑的议题和必须编写的代码。更重要的是,垃圾回收器提供了更高层的保障,可以避免暗藏的内存泄露问题。
1.8.1 集合与迭代器
Java在其标准类库中有容器。有可以满足不同需求的的不同类型的容器。
List类:用于储存序列
Map类:关联数组,用来建立对象之间的关联。
Set类:每种对象类型支持有一个。
Queue/Stack .......
所有容易都有某种用来处理元素置入和取出的方法。
可以使用
迭代器的方法来代替单一选取方式。
迭代器:它是一个用来选取容器中的元素,并把它呈现给迭代器用户的对象。
1.8.2单根继承结构
所有的对象都具有一个共用接口。
保证所有的对象都具有某些功能。
使垃圾回收器的实现变得容易得多。