Java程序设计大学教程第四章 面向对象程序设计面向对象的特点主要概括为抽象性、继承性、
多态性和封装性。本章我们将站在面向对象程序设计原则和方法的高度,围绕这 4个特点讲解面向对象程序设计( OOP)的基本方法。
Java程序设计大学教程
4.1原则和方法面向对象程序设计的重要原则有:
分而治之原则
封装原则
接口原则
信息隐藏原则
一般性原则
可扩展性原则
抽象原则
Java程序设计大学教程
4.1原则和方法面向对象在程序设计中实现的方法:
分解与封装
继承与合成
接口与实现
服务与客户
Java程序设计大学教程
4.2 继承对象的继承是一种在保持对象差异性的同时共享对象相似性的复用。它是源自类的泛化机制。这种抽象机制允许类之间共享代码,
大大减少了代码长度并且使软件易于维护。
对象通过继承,保证了实现部分紧内聚和松耦合的良好特性
Java程序设计大学教程
4.2.1 使用继承
1,基类与派生类
Java中派生类通过 extends
关键字继承基类,并通过
super关键字访问基类的构造函数和方法。
Java中所有的类都继承了
Object类的 toString方法,
我们可以重写并覆盖
toString方法,使之带有对象的具体信息,以便我们跟踪和调试对象。
继承关系形成了树状的类层次结构。继承产生的派生类不能直接访问其基类的 private成员,但所有其他基类成员通过继承成为派生类的成员后,保持它们原来的成员的可访问性,并可在派生类中使用。
面积 = length × width
周长 = 2 × (length + width)
Square需要重写并覆盖基类的
calcPerimeter方法来计算周长。
周长 = 4 × length
Square可以继承基类 Rectangle的
calcArea方法来计算面积,无须另写代码图 4-2在这个 UML类图中,Square继承了 Rectangle,是 Rectangle类的扩展示例程序 4-1 Retangle类( Retangle.java)
public class Retangle {
public Retangle(double l,double w) {
length = l;
width = w;
}
public double calcPerimeter() {
return 2 * (length + width);
}
public double calcArea() {
return length * width;
}
public String toString() {
return "长为 " + length + "宽为 " + width + "的长方形 ";
}
protected double length;
private double width;
}
示例程序 4-2 Square类( Square.java)
public class Square extends Retangle {
public Square(double side) {
super(side,side);
}
public double calcPerimeter() {
return length * 4;
}
public String toString() {
return "边长为 " + length + "的正方形 ";
}
}
Java程序设计大学教程
4.2.1 使用继承
1,基类与派生类
2,继承在果园系统中的使用
Java程序设计大学教程
4.2.2 继承与合成
面向对象程序设计中,通过合成或通过继承都可以在不同的环境中重用已有的设计和实现。但经验表明,除非所有继承的方法都有意义,否则还是应当优先考虑使用合成而不是继承。因为依赖于对象合成技术的设计有更好的重用性或更简单。
Java程序设计大学教程
4.3 多态
多态的意思是具有多种形态,它是面向对象程序设计的重要思想方法。多态在面向对象程序设计中意味着通过动态绑定原理,使用单个变量来引用不同类的对象,自动调用引用对象类的对应方法。
动态绑定机制,可以在运行期判定对象的类型,并调用其相应的方法。也就是说,编译器无需知道对象的类型,
但方法的绑定和调用机制能够找出正确的方法体并加以调用。
同名方法的覆盖( override)和重载( overload)是两种完全不同的机制。
替代原则( substitution principle):基类应该可以用其派生类代换。替代过程也是派生类向上转型的过程。
向上转型是一种常用的安全的类型转换,通过向上转型可实现多态性。
Java程序设计大学教程
4.3.1 多态与动态绑定
1,派生类的对象具有多个类型
2,动态绑定实现多态
public int gain() {
int g=input*2;//收益是投入的两倍
return g;
}
public int gain() {
//收益不变
...
}
public int gain() {
//收益 -200
...
}
public int gain() {
// 收益是投入的 3倍
int g = input * 3;
System.out.println(fruitName +
"投入 " + input + " 净收益 " + g);
return g;
}
覆盖( override)
fruits[i].gain();
程序运行时动态确定实现的
gain方法数组属性索引 0 1 2 3 4
派生类类型 TropicalFruit Berry TropicalFruit Berry CitrusFruit
水果名称 香蕉 葡萄 菠萝 草莓 橘子
fruits[0] = new TropicalFruit("香蕉 ",1000);
fruits[1] = new Berry("葡萄 ",2000);
fruits[2] = new TropicalFruit("菠萝 ",2000);
fruits[3] = new Berry("草莓 ",1000);
fruits[4] = new CitrusFruit("橘子 ",1000);
我们可以像对待基类对象那样对待派生类对象,它们的共性表现在继承下来的同名类成员。所有继承于共同基类的派生类对象可以当做是这些基类的对象。
Food myFood;
Fruit myFruit;
CitrusFruit orange;
orange = new CitrusFruit("橘子 ",1000); //创建橘子对象
myFood = orange(); //相当于 myFood = (Food)orange;
myFood.eat(); //调用的是 CitrusFruit的 eat方法:剥皮吃橘子
myFruit = orange; //相当于 myFruit = (Fruit)orange;
myFruit.eat(); //调用的还是 CitrusFruit的 eat方法:剥皮吃橘子
Java程序设计大学教程
4.3.2 方法的绑定
所谓的方法绑定( Binding)就是建立方法调用( Method Call)和方法本体( Method Body)之间的关联。如果方法是,早绑定,,
,先期绑定,的,也就是在编译时编译器就能准确地判断应该调用的那个方法称为静态绑定方法。 Java中这类方法包括 private,static、
final方法以及构造函数。如果方法是,晚绑定,,,后期绑定,的,
也就是在运行时由虚拟机调用同该对象变量所指对象的实际类型相匹配的方法版本,动态决定的方法,称为动态绑定方法。 Java中除了
private,static,final方法以及构造函数外的其他方法都是动态绑定方法。
Java语言中使用关键字 final来定义常量。但是关键字 final还有另外
2个重要用途:一个是阻止类 (final类 )被继承,另一个是阻止方法
(final方法 )被覆盖( override)。
抽象方法是一种没有实现的方法。定义有抽象方法的类我们称之为抽象类。抽象方法和抽象类都使用 abstract关键字来标识。含有抽象方法的类必须定义为抽象类,但是没有抽象方法的类也可以定义为抽象类。但无论如何,抽象类都不能创建实例。
Java程序设计大学教程
4.4 接口
接口的概念是建立在封装的基础之上。在面向对象程序设计中,封装是指对象的使用者通过预先定义的接口关联到某一对象的服务和数据时,无需知道这些服务是如何实现的。因此接口在面向对象程序设计中有着重要的地位。
在 Java中,抽象类和接口( Interface)都是一种接口抽象机制,符合接口的特点。习惯上我们只把 Java语法中的接口( Interface)作为接口的窄定义。该接口是一种类型,它定义了能被一个类实现的方法。
Java程序设计大学教程
4.4.1 接口的概念接口是指一些方法特征的集合,它关心的是方法的特征定义(例如方法的名称、参数的类型及数量),而不是方法的具体实现。在 Java中,抽象类和接口都是一种接口抽象机制,符合接口的特点。
接口提供了一种抽象机制
接口使即插即用变得可能
接口针对抽象而不是针对实现
Java程序设计大学教程
4.4.2 Java接口
1,定义接口
2,实现接口
3,接口与多重继承
[public] interface 接口名 [ extends 祖先接口名 ] {
返回类型 方法名 (参数列表 );
...
类型 常量字段名 = 值 ;
...
}
[public] class 类名 [ extends 祖先类名 ]
implements 接口名 [,其它接口名,.,]{
//类的实现代码
...
}
下面代码通过实现 Writeable接口和 Eatable接口的 Paper类代码,演示了多重继承的程序设计:
public class Paper implements Eatable,Writeable {
public void eat() {
System.out.println("撕纸吃,"+TASTELESS);
}
public void write() {
System.out.println("在纸上书写,");
}
}
Java程序设计大学教程
4.4.3 接口应用实例
使用接口的好处是便于系统的扩展、维护和重用。接口的使用使得代码模块之间的耦合减弱。具体表现在对象之间的依赖关系弱化为客户 —— 服务的关系,即客户对象请求服务,服务对象提供服务,而接口则成了提供服务的一种契约。
没有经验的程序员设计接口时通常会犯合并接口和预留接口这两个错误。根据接口隔离法则,我们在设计接口时不应该强迫客户端依赖于他们用不上的方法,而是应该提供职责明确、功能专一的最小化接口。除非必要,
应该严格控制接口宽度,避免接口冗余。