资源描述
第5章 接口与多态教案
1. 教学内容
l 接口作用及语法
l 塑型的概念及应用
l 多态的概念及引用
l 构造方法的调用顺序及其中的多态方法
2. 教学要求
l 理解接口、塑型、多态的概念并能熟练应用
l 熟练掌握构造方法的调用顺序,理解编写时需要注意的问题
l 自学内部类的语法结构及其应用场合
3. 授课时间:4学时
4. 授课方式:讲授+案例讲解与演示
5. 课堂组织:
(1)每次课用5分钟时间回顾上次讲课内容
(2)每次课用5分钟时间总结本次课内容
(3)在讲课过程中注意案例分析,调动学生积极性
6. 授课内容:
5.1 接口
l 接口
l 与抽象类一样都是定义多个类的共同属性
l 使抽象的概念更深入了一层,是一个“纯”抽象类,它只提供一种形式,并不提供实现
l 允许创建者规定方法的基本形式:方法名、参数列表以及返回类型,但不规定方法主体
l 也可以包含基本数据类型的数据成员,但它们都默认为static和final
5.1.1 接口的作用及语法
接口
l 接口的作用
l 是面向对象的一个重要机制
l 实现多继承,同时免除C++中的多继承那样的复杂性
l 建立类和类之间的“协议”
l 把类根据其实现的功能来分别代表,而不必顾虑它所在的类继承层次;这样可以最大限度地利用动态绑定,隐藏实现细节
l 实现不同类之间的常量共享
5.1.1 接口的作用及语法
——与抽象类的不同
接口
l 接口允许我们在看起来不相干的对象之间定义共同行为
5.1.1 接口的作用及语法
——例5_1
接口
l 保险公司的例子
l 具有车辆保险、人员保险、公司保险等多种保险业务,在对外提供服务方面具有相似性,如都需要计算保险费(premium)等,因此可声明一个Insurable 接口
l 在UML图中,实现接口用带有空三角形的虚线表示
<<Interface>>
Insurable
Company
Person
Car
5.1.1 接口的作用及语法
接口
l 接口的语法
l 声明格式为
l [接口修饰符] interface 接口名称 [extends 父接口名]{
l …//方法的原型声明或静态常量
l }
l 接口的数据成员一定要赋初值,且此值将不能再更改,允许省略final关键字
l 接口中的方法必须是“抽象方法”,不能有方法体,允许省略public及abstract关键字
5.1.1 接口的作用及语法
——例5_1保险接口的声明
接口
l 例5.1中的Insurable 接口声明如下,可见其中的方法都是抽象方法
l public interface Insurable {
l public int getNumber();
l public int getCoverageAmount();
l public double calculatePremium();
l public Date getExpiryDate();
l }
5.1.1 接口的作用及语法
——例5_2
接口
l 声明一个接口Shape2D,可利用它来实现二维的几何形状类Circle和Rectangle
l 把计算面积的方法声明在接口里
l pi值是常量,把它声明在接口的数据成员里
l interface Shape2D{ //声明Shape2D接口
l final double pi=3.14; //数据成员一定要初始化
l public abstract double area(); //抽象方法
l }
l 在接口的声明中,允许省略一些关键字,也可声明如下
l interface Shape2D{
l double pi=3.14;
l double area();
l }
5.1.2 实现接口
接口
l 接口的实现
l 接口不能用new运算符直接产生对象,必须利用其特性设计新的类,再用新类来创建对象
l 利用接口设计类的过程,称为接口的实现,使用implements关键字
l 语法如下
l public class 类名称 implements 接口名称 {
l /* Bodies for the interface methods */
l /* Own data and methods. */
l }
l 必须实现接口中的所有方法
l 来自接口的方法必须声明成public
5.1.2 实现接口 ——例5_3
接口
l 实现接口Insurable,声明汽车类实现例5.1中的Insurable接口,实现接口中的所有抽象方法
l public class Car implements Insurable {
l public int getPolicyNumber() {
l // write code here
l }
l public double calculatePremium() {
l // write code here
l }
l public Date getExpiryDate() {
l // write code here
l }
l public int getCoverageAmount() {
l // write code here
l }
l public int getMileage() { //新添加的方法
l //write code here
l }
l }
5.1.2 实现接口 ——对象转型
接口
l 对象可以被转型为其所属类实现的接口类型
l getPolicyNumber、calculatePremium是Insurable接口中声明的方法
l getMileage是Car类新添加的方法,Insurable接口中没有声明此方法
l Car jetta = new Car();
l Insurable item = (Insurable)jetta; //对象转型为接口类型
l item.getPolicyNumber();
l item.calculatePremium();
l item.getMileage(); // 接口中没有声明此方法,不可以
l jetta.getMileage(); // 类中有此方法,可以
l ((Car)item).getMileage(); // 转型回原类,可调用此方法了
5.1.2 实现接口 ——例5_4
接口
l 声明Circle与Rectangle两个类实现Shape2D接口
class Circle implements Shape2D
{
double radius;
public Circle(double r)
{
radius=r;
}
public double area()
{
return (pi * radius * radius);
}
}
class Rectangle implements Shape2D
{
int width,height;
public Rectangle(int w,int h)
{
width=w;
height=h;
}
public double area()
{
return (width * height);
}
}
5.1.2 实现接口 ——例5_4运行结果
接口
l 测试类
l public class InterfaceTester {
l public static void main(String args[]){
l Rectangle rect=new Rectangle(5,6);
l System.out.println("Area of rect = " + rect.area());
l Circle cir=new Circle(2.0);
l System.out.println("Area of cir = " + cir.area());
l }
l }
l 运行结果
l Area of rect = 30.0
l Area of cir = 12.56
5.1.2 实现接口 ——例5_5
接口
l 声明接口类型的变量,并用它来访问对象
l public class VariableTester {
l public static void main(String []args)
l {
l Shape2D var1,var2;
l var1=new Rectangle(5,6);
l System.out.println("Area of var1 = " + var1.area());
l var2=new Circle(2.0);
l System.out.println("Area of var2 = " + var2.area());
l }
l }
l 输出结果
l Area of var1 = 30.0
l Area of var2 = 12.56
5.1.2 实现接口 ——MovableObject接口
接口
l MovableObject接口定义了所有“可移动对象”能做的事情
l public interface MovableObject {
l public boolean start();
public void stop();
public boolean turn(int degrees);
public double fuelRemaining();
public void changeSpeed(double kmPerHour);
l }
5.1.2 实现接口 ——MovableObject接口的实现
接口
l Plane、Car、 Train、 Boat 分别实现 MovableObject 接口
l public class Plane implements MovableObject {
l public int seatCapacity;
l public Company owner;
l public Date lastRepairDate;
l //实现MovalbelObject接口的所有方法
l public boolean start() { //启动飞机,成功则返回true }
l public void stop() { //停止 }
l public boolean turn(int degrees) { //转向,成功则返回true}
l public double fuelRemaining() { //返回燃料剩余量 }
l public void changeSpeed(double kmPerHour) { //改变速度 }
l //plane类自己的方法:
l public Date getLastRepairDate() { //... }
l public double calculateWindResistance() { //....}
l }
5.1.2 实现接口 ——RemoteControl类
接口
l 为 MovableObjects安装遥控器(remote control)
l public class RemoteControl {
private MovableObject machine;
l RemoteControl(MovableObject m) {machine = m; }
//按下“启动”按钮:
public void start()
l {
l boolean okay = machine.start();
if (!okay) display("No Response on start");
//...
}
l }
l remote control 构造方法的形参类型为 MovableObject,它可以是Plane, Car, Train, Boat, 等等
5.1.3 多重继承
接口
l 多重继承
l Java的设计以简单实用为导向,不允许一个类有多个父类
l 但允许一个类可以实现多个接口,通过这种机制可实现多重继承
l 一个类实现多个接口的语法如下
l [类修饰符] class 类名称 implements 接口1,接口2, …
l {
l … …
l }
5.1.3 多重继承 ——Car的例子
接口
l Car类可以实现接口Insurable,Drivable,Sellable
l public class Car implements Insurable, Drivable, Sellable
l {
....
l }
5.1.3 多重继承 ——例5_6
接口
l 声明Circle类实现接口Shape2D和Color
l Shape2D具有pi与area()方法,用来计算面积
l Color则具有setColor方法,可用来赋值颜色
l 通过实现这两个接口,Circle类得以同时拥有这两个接口的成员,达到了多重继承的目的
l interface Shape2D{ //声明Shape2D接口
l final double pi=3.14; //数据成员一定要初始化
l public abstract double area(); //抽象方法
l }
l interface Color{
l void setColor(String str); //抽象方法
l }
5.1.3 多重继承 ——例5_6
接口
class Circle implements Shape2D,Color // 实现Circle类
{
double radius;
String color;
public Circle(double r) //构造方法
{
radius=r;
}
public double area() //定义area()的处理方式
{
return (pi*radius*radius);
}
public void setColor(String str) //定义setColor()的处理方式
{
color=str;
System.out.println("color="+color);
}
}
5.1.3 多重继承 ——例5_6运行结果
接口
l 测试类
l public class MultiInterfaceTester{
l public static void main(String args[]) {
l Circle cir;
l cir=new Circle(2.0);
l cir.setColor("blue");
l System.out.println("Area = " + cir.area());
l }
l }
l 输出结果
l color=blue
l Area = 12.56
5.1.4 接口的扩展
接口
l 接口的扩展
l 接口可通过扩展的技术派生出新的接口
l 原来的接口称为基本接口(base interface)或父接口(super interface)
l 派生出的接口称为派生接口(derived interface)或子接口(sub interface)
l 派生接口不仅可以保有父接口的成员,同时也可加入新成员以满足实际问题的需要
l 实现接口的类也必须实现此接口的父接口
l 接口扩展的语法
l interface 子接口的名称 extends 父接口的名称1,父接口的名称2,…
l {
l … …
l }
5.1.4 接口的扩展 ——例5_7
接口
l Shape是父接口,Shape2D与Shape3D是其子接口。Circle类及Rectangle类实现接口Shape2D,而Box类及Sphere类实现接口Shape3D
Shape接口
Shape2D接口
Shape3D接口
Sphere类
Box类
Rectangle类
Circle类
5.1.4 接口的扩展 ——例5_7
接口
l 部分代码如下
l // 声明Shape接口
l interface Shape{
l double pi=3.14;
l void setColor(String str);
l }
l //声明Shape2D接口扩展了Shape接口
l interface Shape2D extends Shape {
l double area();
l }
5.1.4 接口的扩展 ——例5_7
接口
class Circle implements Shape2D {
double radius;
String color;
public Circle(double r) { radius=r; }
public double area() {
return (pi*radius*radius);
}
public void setColor(String str){
color=str;
System.out.println("color="+color);
}
}
public class ExtendsInterfaceTester{ //测试类
public static void main(String []args) {
Circle cir;
cir=new Circle(2.0);
cir.setColor("blue");
System.out.println("Area = " + cir.area());
}
}
5.1.4 接口的扩展 ——例5_7运行结果
接口
l 运行结果
l color=blue
l Area = 12.56
l 说明
l 首先声明了父接口Shape,然后声明其子接口Shape2D
l 之后声明类Circle实现Shape2D子接口,因而在此类内必须明确定义setColor()与area()方法的处理方式
l 最后在主类中我们声明了Circle类型的变量cir并创建新的对象,最后通过cir对象调用setColor()与area()方法
5.1.4 接口的扩展 ——Insurable接口的例子
接口
l FixedInsurable 和DepreciatingInsurable接口
l 都继承了Insurable接口
l 实现它们类也必须实现Insurable接口中的所有方法
l public interface DepreciatingInsurable extends Insurable {
public double computeFairMarketValue();
l }
l public interface FixedInsurable extends Insurable {
public int getEvaluationPeriod();
l }
5.2 塑型
l 塑型(type-casting)
l 又称为类型转换
l 方式
l 隐式(自动)的类型转换
l 显式(强制)的类型转换
5.2.1 塑型的概念
塑型
l 塑型的对象包括
l 基本数据类型
l 将值从一种形式转换成另一种形式
l 引用变量
l 将对象暂时当成更一般的对象来对待,并不改变其类型
l 只能被塑型为
l 任何一个父类类型
l 对象所属的类实现的一个接口
l 被塑型为父类或接口后,再被塑型回其本身所在的类
5.2.1 塑型的概念 ——一个例子
塑型
l Manager对象
l 可以被塑型为Employee、Person、Object或Insurable,
l 不能被塑型为Customer、Company或Car
Object
Person
Employee
Customer
Manager
Company
Car
<<Interface>>
Insurable
5.2.1 塑型的概念 ——隐式(自动)的类型转换
塑型
l 基本数据类型
l 相容类型之间存储容量低的自动向存储容量高的类型转换
l 引用变量
l 被塑型成更一般的类
l Employee emp;
l emp = new Manager(); //将Manager类型的对象直接赋给
l //Employee类的引用变量,系统会
l //自动将Manage对象塑型为Employee类
l 被塑型为对象所属类实现的接口类型
l Car jetta = new Car();
l Insurable item = jetta;
5.2.1 塑型的概念 ——显式(强制)的类型转换
塑型
l 基本数据类型
l (int)871.34354; // 结果为 871
l (char)65; // 结果为‘A’
l (long)453; // 结果为453L
l 引用变量:还原为本来的类型
l Employee emp;
l Manager man;
l emp = new Manager();
l man = (Manager)emp; //将emp强制塑型为本来的类型
5.2.2 塑型的应用
塑型
l 塑型应用的场合包括
l 赋值转换
l 赋值号右边的表达式类型或对象转换为左边的类型
l 方法调用转换
l 实参的类型转换为形参的类型
l 算数表达式转换
l 算数混合运算时,不同类型的项转换为相同的类型再进行运算
l 字符串转换
l 字符串连接运算时,如果一个操作数为字符串,一个操作数为数值型,则会自动将数值型转换为字符串
5.2.2 塑型的应用
塑型
l 当一个类对象被塑型为其父类后,它提供的方法会减少
l 当Manager对象被塑型为Employee之后,它只能接收getName()及getEmployeeNumber()方法,不能接收getSalary()方法
l 将其塑型为本来的类型后,又能接收getSalary()方法了
5.2.3 方法的查找
塑型
l 如果在塑型前和塑型后的类中都提供了相同的方法,如果将此方法发送给塑型后的对象,那么系统将会调用哪一个类中的方法?
l 实例方法的查找
l 类方法的查找
5.2.3 方法的查找 ——实例方法的查找
塑型
l 从对象创建时的类开始,沿类层次向上查找
Manager man = new Manager();
Employee emp1 = new Employee();
Employee emp2 = (Employee)man;
putePay(); // 调用Employee类中的computePay()方法
putePay(); // 调用Manager类中的computePay()方法
putePay(); // 调用Manager类中的computePay()方法
5.2.3 方法的查找 ——类方法的查找
塑型
l 总是在引用变量声明时所属的类中进行查找
Manager man = new Manager();
Employee emp1 = new Employee();
Employee emp2 = (Employee)man;
man.expenseAllowance(); //in Manager
emp1.expenseAllowance(); //in Employee
emp2.expenseAllowance(); //in Employee!!!
5.3 多态的概念
l 多态
l 是指不同类型的对象可以响应相同的消息
l 从相同的基类派生出来的多个类型可被当作同一种类型对待,可对这些不同的类型进行同样的处理,由于多态性,这些不同派生类对象响应同一方法时的行为是有所差别的
l 例如
l 所有的Object类的对象都响应toString()方法
l 所有的BankAccount类的对象都响应deposit()方法
5.3.1 多态的目的
多态的概念
l 多态的目的
l 所有的对象都可被塑型为相同的类型,响应相同的消息
l 使代码变得简单且容易理解
l 使程序具有很好的“扩展性”
5.3.1 多态的目的 ——一个例子
多态的概念
l 绘图——直接的方式
l 希望能够画出任意子类型对象的形状,可以在Shape 类中声明几个绘图方法,对不同的实际对象,采用不同的画法
l if (aShape instanceof Circle) aShape.drawCircle();
l if (aShape instanceof Triangle) aShape.drawTriangle();
l if (aShape instanceof Rectangle)aShape.drawRectangle();
5.3.1 多态的目的 ——一个例子
多态的概念
l 绘图——更好的方式
l 在每个子类中都声明同名的draw()方法
l 以后绘图可如下进行
l Shape s = new Circle();
l s.draw();
l Circle属于Shape的一种,系统会执行自动塑型
l 当调用方法draw时,实际调用的是Circle.draw()
l 在程序运行时才进行绑定,接下来介绍绑定的概念
5.3.2 绑定的概念
多态的概念
l 绑定
l 指将一个方法调用同一个方法主体连接到一起
l 根据绑定时期的不同,可分为
l 早期绑定
l 程序运行之前执行绑定
l 晚期绑定
l 也叫作“动态绑定”或“运行期绑定
l 基于对象的类别,在程序运行时执行绑定
5.3.2 绑定的概念 ——例5_8
多态的概念
l 仍以绘图为例,所有类都放在binding包中
l 基类Shape建立了一个通用接口
l class Shape {
l void draw() {}
l void erase() {}
l }
l 派生类覆盖了draw方法,为每种特殊的几何形状都提供独一无二的行为
l class Circle extends Shape {
l void draw()
l { System.out.println("Circle.draw()"); }
l void erase()
l { System.out.println("Circle.erase()"); }
l }
5.3.2 绑定的概念 ——例5_8
多态的概念
class Square extends Shape {
void draw()
{ System.out.println("Square.draw()"); }
void erase()
{ System.out.println("Square.erase()"); }
}
class Triangle extends Shape {
void draw()
{ System.out.println("Triangle.draw()"); }
void erase()
{ System.out.println("Triangle.erase()"); }
}
5.3.2 绑定的概念 ——例5_8
多态的概念
l 对动态绑定进行测试如下
l public class BindingTester{
l public static void main(String[] args) {
l Shape[] s = new Shape[9];
l int n;
l for(int i = 0; i < s.length; i++) {
l n = (int)(Math.random() * 3);
l switch(n) {
l case 0: s[i] = new Circle(); break;
l case 1: s[i] = new Square(); break;
l case 2: s[i] = new Triangle();
l }
l }
l for(int i = 0; i < s.length; i++) s[i].draw();
l }
l }
5.3.2 绑定的概念 ——例5_8运行结果
多态的概念
l 运行结果
l Square.draw()
l Triangle.draw()
l Circle.draw()
l Triangle.draw()
l Triangle.draw()
l Circle.draw()
l Square.draw()
l Circle.draw()
l Triangle.draw()
l 说明
l 编译时无法知道s数组元素的具体类型,运行时才能确定类型,所以是动态绑定
l 在主方法的循环体中,每次随机生成指向一个Circle、Square或者Triangle的引用
5.4 多态的应用
多态的概念
l 多态的应用
l 技术基础
l 向上塑型技术:一个父类的引用变量可以指向不同的子类对象
l 动态绑定技术:运行时根据父类引用变量所指对象的实际类型执行相应的子类方法,从而实现多态性
5.4 多态的应用(续) ——例5_9
多态的概念
l 声明一个抽象类Driver及两个子类FemaleDriver及MaleDriver
l 在Diver类中声明了抽象方法drives,在两个子类中对这个方法进行了重写
l public abstract class Driver
l {
l public Driver( ) { }
l public abstract void drives( );
l }
5.4 多态的应用(续) ——例5_9
多态的概念
public class FemaleDriver extends Driver {
public FemaleDriver( ) { }
public void drives( ) {
System.out.println("A Female driver drives a vehicle.");
}
}
public class MaleDriver extends Driver {
public MaleDriver( ) { }
public void drives( ) {
System.out.println("A male driver drives a vehicle.");
}
}
5.4 多态的应用(续) ——例5_9
多态的概念
l public class Test1
l {
l static public void main(Str
展开阅读全文