Download presentation
Presentation is loading. Please wait.
Published by租 曹 Modified 8年之前
1
第五章 类的继承和派生 Inheritance/extends/derive
2
教学目标 理解继承的概念和作用 派生类的定义 理解访问修饰符 protected 方法的重写 继承下的构造函数的使用 继承下的 finalize 方法的使用 理解超类和子类的关系
3
5.1 继承的概念和软件的重用性 继承是从已有的类中派生出新的类。 新的类能吸收已有类的数据属性和行为 ; 并能扩展新的能力。 类和类之间的继承关系可以用 UML 符号表示如图 5-1, 父类又叫超类或基类, 子类又叫派生类。 父类是子类的一般化,子类是父类的特化(具体化)。 超类或基类 父类 子类 派生类 图 5-1 继承关系 super/base/parent child/derived
4
5.1 继承的概念和软件的重用性 如表 5-1 所示,列出了几个超类和子类的实际例子。 超类或基类 父类 子类 派生类 图 5-1 继承关系 超 类子 类 学生研究生、本科生、小学生 形状三角形、圆、矩形 雇员教师、医生、职员 交通工具轿车、卡车、公交车 水果苹果、梨、桃、桔 表 5-1 继承例子
5
“is-a” 关系 : 是类之间的继承关系。 子类的对象可当作超类对象。但反过来,不能把超 类对象可当作子类对象。 例如,轿车可看成是交通工具,但不能把交通工具 看成就是轿车。 “has-a” 关系 : 代表类之间的组合(参见 4.9 节)。 在 “has-a” 关系中一个对象包含一个或多个其他对 象的引用成员。 如,轿车由方向盘、轮子、发动机等组成。 5.1 继承的概念和软件的重用性(续)
6
继承分为单继承和多继承。 单继承是指一个子类最多只能有一个父类。 多继承是一个子类可有二个以上的父类。 由于多继承会带来二义性,在实际应用中应尽量 使用单继承。 Java 类只支持单继承,而接口支持多继承。 5.1 继承的概念和软件的重用性(续)
7
object Win DialogWin 单继承,in java Class 1 Class 4 Class 2 Class 3 多继承,in C++ 单继承与多继承例子
8
5.1 继承的概念和软件的重用性(续) 继承使软件的代码得到重用。 在继承关系中, 子类通过吸收已有类的数据(属性)和方法(行 为) 并增加新功能或修改已有功能来创建新类。 软件的重用性不仅节省了程序的开发时间,还促进了 经过验证和调试的高质量软件的重用,这增加实现系 统的效率。 在 java 中, Object 类定义和实现了 Java 系统所需要的众 多类的共同行为,它是所有类的根类,所有的类都是 由这个类继承、扩充而来的。
9
5.2 派生类的定义 派生类定义的一般格式为: [ 类修饰符 ] class 子类名 extends 父类名 { 成员变量定义; 成员方法定义; } 派生类的定义中,用关键字 extends 来明确指出 它所继承的超类。 例 5-1 通过继承来定义派生类 例 5-1
10
5.2 派生类的定义(续) class Automobile{ int Number; void setNumber(int Num){ Number=Num; } void showNumber(){ System.out.println("Automobile number:"+Number); } } 超类
11
5.2 派生类的定义(续) class Truck extends Automobile{ int capacity; void setCapacity(int truckCapacity){ capacity=truckCapacity; } void showCapacity(){ System.out.println ( "Truck Capacity:"+capacity ); } } 派生类
12
5.2 派生类的定义(续) class AutomobileExtends{ public static void main(String args[]){ Truck tc=new Truck(); tc.setNumber(8888); tc.setCapacity(10); tc.showNumber(); tc.showCapacity(); } } 该程序运行的结果为: Automobile number:8888 Truck Capacity:10 派生类使用从超类中继承 的方法 setNumber 派生类使用从超类中继承的方法 showNumber
13
5.3 作用域和继承 第 4 章讨论了成员访问控制修饰符: public 、 private 、 package 和 protected 。 超类 public 的成员可以在超类中使用,也可以在子类使用, 程序可以在任何地方访问 public 超类成员。 超类的 private 成员仅在超类中使用,在子类中不能被访问。 超类 protected 成员, 可在子类和同一包内其他类被访问。 超类 package 成员, 可在同一包内其他类被访问。 子类从超类中继承成员时,超类的所有 public 和 protected 成 员在子类中,都保持它们原有的访问修饰符。
14
5.4 方法的重新定义 (overriding) 如果在子类中定义的某个方法与父类的某个方法有相同 方法署名(方法头),则称子类重新定义( overriding )了 父类的该方法,或称重写或覆盖。 子类的对象调用这个方法时,将使用子类中定义的方法, 对它而言,父类中定义的方法就 “ 看不见 ” 了。 如要在子类的方法中要使用超类的这个被重写的方法, 用 : super. 超类同名方法 ( … ) 。 例 5-2 方法的重写 例 5-2
15
Point 类的设计: 成员变量 :int x , y 成员方法 : setX(int ) , getX() , setY(int) , getY() , toString() ; Point(), Point(int xValue,int yValue) Circle 类的设计: 成员变量 :x , y// 继承自 Point 类 radius 成员方法 : setX() , getX () , setY () , getY () // 继承自 Point 类 set Radius () , getRadius () , getDiameter () , getCircumference () toString() // 重写父类同名方法 getArea() Circle (), Circle ( int xValue, int yValue, double radiusValue )
16
5.4 方法的重新定义 (overriding) (续) Point.java 文件的部分代码: …… public String toString(){ return "[" + x + ", " + y + "]"; } …… Circle.java 文件的部分代码: …… public String toString(){ return "Center = " +super.toString()+" Radius = " + radius; } …… 重写了超类 Point 类中 的 toString 方法 通过 super 调用超类中的被重写的 toString 方法
17
5.5 继承下的构造函数和 finalize 方法 继承下的构造函数的调用次序:子类对象的实例化过程开 始于一系列的构造函数调用, 子类构造函数在执行自己的任务之前,将显式地(通过 super 引 用)或隐式地(调用超类的默认构造函数或无参数构造函数)调 用其直接超类的构造函数。类似地,如果超类派生于另一个类, 则要求超类的构造函数调用层次结构中上一级类的构造函数,依 此类推。在调用请求中,最先调用的构造函数总是 Object 类的构 造函数。最后才会执行原有的子类构造函数。 继承下的 finalize 方法的调用次序 类层次结构中子类 finalize 方法调用应先于超类的 finalize 方法, 直至最后调用 Object 超类的 finalize 方法。 finalize 方法的定义格式 : void finalize()
18
例 5-3 例 5-3 继承下的构造函数和 finalize 方法
19
5.6 超类和子类的关系(一) 再次使用点 — 圆继承层次来讨论超类与子 类的关系。 为了使圆类继承点类并能访问点类中的成 员变量,可将点类中的 x 和 y 定义成 protected 的成员. 例 5-4 中, Circle2 类通过继承 Point2 类,就 可以在 Circle2 类中访问它的超类( Point2 类) 的 protected 和 public 成员了。 例 5-4 例 5-4 使用 protected 数据的点 - 圆层次
20
5.6 超类和子类的关系(二) 但在使用 protected 成员变量时,会产生两个问题 : 子类可将非法值赋给变量,导致该变量处于非法状态。 例如,如果将 Circle2 的成员变量 radius 声明为 protected , 则它的子类就能够将负值赋给 radius 变量。 编写的子类 Circle2 方法更依赖于超类 Point2 实现。 例如,如果由于某种原因将成员变量 x 和 y 的名称改为 xCoordinate 和 yCoordinate ,则子类直接引用这些超类成员变 量的所有地方都必须进行相应地修改。 为了使子类应依赖于超类服务,而不应依赖于超类实现 : 把超类中的成员变量声明为 private ,并在超类中定义访问 这些 private 成员变量的 public 型的方法,
21
例 5-5 把超类中的成员变量声明为 private , 在子类中使用从超类中继承过来的方法对这些 私有成员变量进行访问。
22
//Point3.java public class Point2 { private int x; private int y; …… public void setX( int xValue ){ x = xValue; } public int getX(){ return x; } public void setY( int yValue ){ y = yValue; } public int getY(){ return y; } …… }
23
//Circle3.java public class Circle3 extends Point3 { private double radius; public Circle3(){ // 隐式调用超类的无参构造方法 } public Circle3( int xValue, int yValue, double radiusValue ){ super( xValue, yValue ); // 显式调用超类的构造方法 setRadius( radiusValue ); }...... public String toString(){ // 调用超类的 toString 方法 return "Center = " + super.toString() + "; Radius = " + getRadius(); }
24
5.7 继承的程序设计举例(一) 下面让我们来看一个具有 3 级继承 层次的例子。这 3 级为点 — 圆 — 圆柱 体。它们之间的继承关系如图 5-3 所 示。 例 5-6 例 5-6 继承的程序设计举例 图 5-3 三级继承层次
25
Point 类的设计: 成员变量 :int x , y 成员方法 :setX , getX , setY , getY , toString. Point(), Point(int xValue,int yValue) Circle 类的设计: 成员变量 : double radius 成员方法 : setRadius , getRadius , getDiameter , getCircumference , getArea,toString Circle( ), Circle(int xValue,int yValue, double radiusValue ) Clinder 类的设计 : 成员变量 : double hight 成员方法 : setHight , getHight , getArea, toString Cylinder( int xValue, int yValue, double radiusValue,double heightValue )
26
小结 继承作用 : 在原有类的基础上派生出高效的子类。 子类可以使用超类中被声明为 protected 和 public 的成员, 也可以在子类中重写超类中的方法,使该方法的执行 更符合子类的情况。 超类的构造函数不能够被继承,但当调用子类的构造 函数时,将首先要隐式或显式地调用超类的构造函数。 如果类层次结构中的类声明了它们自己的 finalize 方法, 则子类方法 finalize 的最后一个操作应调用超类的 finalize 方法,以确保在垃圾收集器回收对象内存时, 能够正确的结束对象的所有部分。
27
[ 作业与实验 ] 作业 书 P96: 1 、 2 、 8 、 9 、 10 、 11. 实验 习题解答与实验书 P83 : 实验 8
Similar presentations