第
5
章
继承与多态
本章学习目标
● 掌握子类定义的方法。
● 理解子类构造方法的执行过程
。
理解关键字super的作用,掌握其使用方法
。
●

● 理解方法重写和多态性的概念。
● 掌握关键字final的使用方法。
● 掌握包的定义和导入的方法。
在第4章,重点介绍了面向对象程序设计的基本要素———类和对象,可使读
者掌握最基本的面向对象程序设计的方法。在此基础上,本章将进一步深入讨
论面向对象中的继承和多态机制。首先,本章将介绍继承的基本概念、子类的
定义方法,并讨论不同场景下的类成员的访问权限。接着,介绍方法重写的概
念,并以此引出类的多态性讨论。最后,本章还将介绍Java中的包机制,并进一
步讨论与包相关的访问权限。通过本章的学习,读者可以比较全面地掌握面向
对象程序设计的方法。

..5.1 
继承的基本概念

继承是面向对象程序设计的重要特征之一,其含义是以已有类为基础,创
建出新类,新类除了具备已有类的成员之外,还可以增加新的成员以满足解决
问题的需求。在继承中,已有类称为父类(基类或超类), 新类称为子类(派生
类)。Java中支持单继承机制,即每个类只有唯一的父类,C++中采用了多继承
机制,即每个类可以有多个父类,这是二者在继承上的重要区别。事实上,使用
单继承机制的Jaa中, aa.ag包中的Obect类,

v所有的类都继承自jvlnj这样能够
保证所有的对象都拥有某些功能。此外,单继承机制也使垃圾收集器的实现更
加便捷。

v如图5.

Jaa中的继承遵循层次化的树状结构,1所示,舰艇、客轮和货轮均
继承自轮船,而舰艇又派生出3个子类,分别是驱逐舰、巡洋舰和航空母舰。这


第5章 继承与多态 99 
表示舰艇、客轮和货轮都具有轮船所具备的共同属性,例如,都有长度、宽度、排水量等属
性;同时,它们又有各自特有的特征,例如,舰艇具有舰员配置、武器系统、动力装置等属
性,客轮具有客舱、娱乐设施、救生设施等属性,货轮有载货量、起重机、升降平台等属性。
驱逐舰、巡洋舰和航空母舰都具有舰艇的共同属性(当然也具有轮船的共同属性),此外还拥
有各自独有的属性,如航空母舰有舰载机等。需要说明的是,如果定义类时没有明确指明该
类的父类,则它默认继承自java.lang.Object类。Object类是Java中所有类的共同父类。
图5.1 类的层次继承树状图
.. 5.2 子类的定义
在Java中,继承是通过定义子类来实现的。一般来说,类中公共的属性放到父类中, 
而特殊的内容放到子类定义,这样做的明显优势是能够提高代码的复用性。
5.2.1 子类的定义格式
在Java中,定义一个子类的语法格式如下。 
[public]class 子类名extends 父类名
{ 
类体
}
事实上,在第4章中已经学习过类定义的完整格式,此处只介绍和子类定义相关的内
容。关键字extends是定义子类最重要的元素,extends前的类名表示子类,其后的类名
表示父类。继承的特性如下。
● 子类可以继承父类中所有非private权限的成员。
● 类的继承不改变类成员的访问权限,即子类继承的成员的访问权限和父类中一致。
● 父类的构造方法不能被子类所继承。
ex5_1 
下面给出一个子类定义的具体实例。
【例5-1】 子类定义实例。 
0001 class NavalVessel 
0002 {

1 00 Java程序设计(微课版) 
0003 String name; 
0004 float length, width; 
0005 int displacement; 
0006 int maxSpeed; 
0007 int numberOfCrews; 
0008 void showInfo() 
0009 { 
0010 System.out.println("【舰艇信息】"); 
0011 System.out.println("名称: " + name); 
0012 System.out.println("长度(米): " + length); 
0013 System.out.println("宽度(米): " + width); 
0014 System.out.println("排水量(吨): " + displacement); 
0015 System.out.println("最大航速(节): " + maxSpeed); 
0016 System.out.println("舰员数量: " + numberOfCrews); 
0017 } 
0018 } 
0019 class AircraftCarrier extends NavalVessel 
0020 { 
0021 int numberOfAircrafts; 
0022 int numberOfPoilts; 
0023 String takeoffMode; 
0024 AircraftCarrier(String n, float len, float wid, int dis, int ms, 
0025 int noc, int noa, int nop, String tm) 
0026 { 
0027 name = n; 
0028 length = len; 
0029 width = wid; 
0030 displacement = dis; 
0031 maxSpeed = ms; 
0032 numberOfCrews = noc; 
0033 numberOfAircrafts = noa; 
0034 numberOfPoilts = nop; 
0035 takeoffMode = tm; 
0036 } 
0037 void showInfo() 
0038 { 
0039 System.out.println("【航空母舰信息】"); 
0040 System.out.println("名称: " + name); 
0041 System.out.println("长度(米): " + length); 
0042 System.out.println("宽度(米): " + width); 
0043 System.out.println("排水量(吨): " + displacement); 
0044 System.out.println("最大航速(节): " + maxSpeed); 
0045 System.out.println("舰员数量: " + numberOfCrews);

第5章 继承与多态1 01 
0046 System.out.println("舰载机数量: " + numberOfAircrafts); 
0047 System.out.println("飞行员数量: " + numberOfPoilts); 
0048 System.out.println("舰载机起飞方式: " + takeoffMode); 
0049 } 
0050 } 
0051 public class Example5_1 
0052 { 
0053 public static void main(String[]args) 
0054 { 
0055 AircraftCarrier ac = new AircraftCarrier("辽宁号", 304.5f, 75f, 
0056 67500, 32, 1960, 36, 626, "滑跃起飞"); 
0057 ac.showInfo(); 
0058 } 
0059 } 
【运行结果】
程序运行结果如图5.2所示。
图5.2 子类定义实例输出
【程序说明】
例5-1定义了父类NavalVessel和子类AircraftCarrier。父类NavalVessel拥有成员
name、length、width、displacement、maxSpeed 和numberOfCrews,子类AircraftCarrier 
在继承这些成员的基础上又增加了成员numberOfAircrafts(舰载机数量)、numberOfPoilts 
(飞行员数量)和takeoffMode(舰载机起飞模式),因此,类AircraftCarrier一共有9个成
员变量。程序第24~36行定义了AircraftCarrier类的构造方法,其作用是利用形参对其
所属的9个成员变量进行赋值。程序第37~49行定义了showInfo()的方法,该方法与
父类中的showInfo()方法重名,且参数列表也相同(均为空),这种现象称为方法重写
(overriding)。
5.2.2 子类构造方法
当使用new运算符创建子类对象时,Java虚拟机所执行的步骤如下。

1 02 Java程序设计(微课版) 
第一步:调用父类构造方法,如存在多级继承,则递归地调用上级父类的构造方法。
第二步:根据子类中各个成员的声明顺序,调用各个成员的初始值设定。
第三步:调用子类自身的构造方法。
ex5_2 
【例5-2】 子类构造方法执行顺序实例。 
0001 class Ship 
0002 { 
0003 Ship() 
0004 { 
0005 System.out.println("【调用Ship 类构造方法,开始建造轮船…】"); 
0006 } 
0007 } 
0008 class NavalVessel extends Ship 
0009 { 
0010 String name; 
0011 float length, width; 
0012 int displacement; 
0013 int maxSpeed; 
0014 int numberOfCrews; 
0015 { 
0016 name = "山东号"; 
0017 length = 315; 
0018 width = 75; 
0019 displacement = 65000; 
0020 System.out.println("舰艇名称: " + name); 
0021 System.out.println("舰艇长度(米): " + length); 
0022 System.out.println("舰艇宽度(米): " + width); 
0023 System.out.println("排水量(吨): " + displacement); 
0024 } 
0025 NavalVessel() 
0026 { 
0027 System.out.println("【调用NavalVessel 类构造方法,开始建造舰艇…】"); 
0028 } 
0029 } 
0030 class AircraftCarrier extends NavalVessel 
0031 { 
0032 int numberOfAircrafts; 
0033 String takeoffMode; 
0034 { 
0035 numberOfAircrafts = 48; 
0036 takeoffMode = "滑跃起飞"; 
0037 System.out.println("舰载机数量: " + numberOfAircrafts); 
0038 System.out.println("舰载机起飞方式: " + takeoffMode);

第5章 继承与多态1 03 
0039 } 
0040 AircraftCarrier() 
0041 { 
0042 System.out.println("【调用AircraftCarrier 类构造方法,开始建造航空母
舰…】"); 
0043 } 
0044 } 
0045 public class Example5_2 
0046 { 
0047 public static void main(String[]args) 
0048 { 
0049 AircraftCarrier ac = new AircraftCarrier(); 
0050 } 
0051 } 
【运行结果】
程序运行结果如图5.3所示。
图5.3 子类构造方法执行顺序实例输出
【程序说明】
程序定义了3 个类,Ship 是父类,NavalVessel是Ship 的子类,AircraftCarrier是
NavalVessel的子类。程序第49行创建了类AircraftCarrier的对象ac。从图5.3的输出
可以分析得出,欲创建子类的对象,必先递归地调用其父类的构造方法,然后执行子类的
成员初始化(例如程序第15~24行、第34~39行),最后再执行子类自身的构造方法。
5.2.3 super关键字
继续分析例5-2,在类AircraftCarrier的构造方法中,并未看到任何调用其父类
NavalVessel类构造方法的语句。事实上,如果在子类构造方法中没有显式地调用父类
构造方法,则系统会自动在子类构造方法第一句调用父类的无参构造方法。
由于构造方法是不能被继承的,在子类中调用父类的构造方法需要使用到关键字
super,其语法格式为:

1 04 Java程序设计(微课版) 
super(形参列表); 
接下来,对例5-1的代码进行修改。
ex5_3 
【例5-3】 super调用父类构造方法实例。 
0001 class NavalVessel 
0002 { 
0003 String name; 
0004 float length, width; 
0005 int displacement; 
0006 int maxSpeed; 
0007 int numberOfCrews; 
0008 NavalVessel(String name, float length, float width, int displacement, 
0009 int maxSpeed, int numberOfCrews) 
0010 { 
0011 this.name = name; 
0012 this.length = length; 
0013 this.width = width; 
0014 this.displacement = displacement; 
0015 this.maxSpeed = maxSpeed; 
0016 this.numberOfCrews = numberOfCrews; 
0017 } 
0018 void showInfo() 
0019 { 
0020 System.out.println("【舰艇信息】"); 
0021 System.out.println("名称: " + name); 
0022 System.out.println("长度(米): " + length); 
0023 System.out.println("宽度(米): " + width); 
0024 System.out.println("排水量(吨): " + displacement); 
0025 System.out.println("最大航速(节): " + maxSpeed); 
0026 System.out.println("舰员数量: " + numberOfCrews); 
0027 } 
0028 } 
0029 class AircraftCarrier extends NavalVessel 
0030 { 
0031 int numberOfAircrafts; 
0032 int numberOfPoilts; 
0033 String takeoffMode; 
0034 AircraftCarrier(String name, float length, float width, int displacement, 
0035 int maxSpeed, int numberOfCrews, int numberOfAircrafts, 
int numberOfPoilts, String takeoffMode) 
0036 { 
0037 super(name, length, width, displacement, maxSpeed, numberOfCrews);

第5章 继承与多态1 05 
0038 this.numberOfAircrafts = numberOfAircrafts; 
0039 this.numberOfPoilts = numberOfPoilts; 
0040 this.takeoffMode = takeoffMode; 
0041 } 
0042 void showInfo() 
0043 { 
0044 super.showInfo(); 
0045 System.out.println("【航空母舰信息】"); 
0046 System.out.println("舰载机数量: " + numberOfAircrafts); 
0047 System.out.println("飞行员数量: " + numberOfPoilts); 
0048 System.out.println("舰载机起飞方式: " + takeoffMode); 
0049 } 
0050 } 
0051 public class Example5_3 
0052 { 
0053 public static void main(String[]args) 
0054 { 
0055 AircraftCarrier ac = new AircraftCarrier("辽宁号", 304.5f, 75f, 
0056 67500, 32, 1960, 36, 626, "滑跃起飞"); 
0057 ac.showInfo(); 
0058 } 
0059 } 
【运行结果】
程序运行结果如图5.4所示。
图5.4 super调用父类构造方法实例输出
【程序说明】
程序第37行是子类显式地调用父类的构造方法,通过它完成相关成员变量(name、
length、width、displacement、maxSpeed和numberOfCrews)的初始化;程序第38~40行, 
完成其余3个成员变量numberOfAircrafts、numberOfPoilts和takeoffMode的赋值,一

1 06 Java程序设计(微课版) 
定程度上减少了冗余代码;程序第44行关键字super的作用并非是调用父类构造方法, 
而是访问父类的其他成员方法。
下面来介绍关键字super的其他功能。关键字super除了可以调用父类构造方法
外,还可以访问父类中的成员变量和成员方法,其语法格式分别为: 
super.父类成员变量名
和 
super.父类成员方法名
ex5_4 
【例5-4】 super访问父类成员实例。 
0001 class NavalVessel 
0002 { 
0003 String name = "南昌号"; 
0004 void showInfo() 
0005 { 
0006 System.out.println("【舰艇信息】"); 
0007 System.out.println("本舰艇名称: " + name); 
0008 } 
0009 } 
0010 class AircraftCarrier extends NavalVessel 
0011 { 
0012 String name = "山东号"; 
0013 void showInfo() 
0014 { 
0015 super.showInfo(); 
0016 System.out.println("【航空母舰信息】"); 
0017 System.out.println("舰艇名称: " + super.name); 
0018 System.out.println("航空母舰名称: " + this.name); 
0019 } 
0020 } 
0021 public class Example5_4 
0022 { 
0023 public static void main(String[]args) 
0024 { 
0025 AircraftCarrier ac = new AircraftCarrier(); 
0026 ac.showInfo(); 
0027 } 
0028 } 
【运行结果】
程序运行结果如图5.5所示。

第5章 继承与多态1 07 
图5.5 super访问父类成员实例输出 
【程序说明】
程序定义了两个类,分别是父类NavalVessel和子类AircraftCarrier,两个类中都有
成员变量name。当子类和父类拥有相同的成员变量时,子类会隐藏从父类继承的成员变
量。NavalVessel类对象默认的name为“南昌号”,AircraftCarrier类对象默认的name 
为“山东号”。程序第15行,子类通过关键字super访问父类的showInfo()方法,因此输
出“本舰艇名称:南昌号”;程序第17行,super.name访问父类对象被隐藏的成员变量
name,因此输出“舰艇名称:南昌号”;程序第18 行,this.name访问的是子类对象的
name,因此输出“航空母舰名称:山东号”。
【注意】
● 使用super可以访问父类的构造方法,且必须放置在子类构造方法的第一条语句。
● 使用super可以访问父类中被子类所隐藏的成员变量和成员方法。
.. 5.3 继承的访问权限
在前面章节中已经介绍了访问权限修饰符,并通过表格的形式给出了不同的访问权
限修饰符在各种情形下的可访问性。下面将结合继承,进一步探讨成员变量(成员方法同
理)在子类和在同一包中其他类的访问权限。包的概念在后续章节才会学习到,此处只需
知道同一个源文件中的类必然属于同一个包,至于不同包中的类的成员的访问权限,将在
后续章节继续讨论。
ex5_5 
【例5-5】 访问权限实例。 
0001 class A 
0002 { 
0003 public int a; 
0004 private int b; 
0005 protected int c; 
0006 int d; 
0007 A(int a, int b, int c, int d) 
0008 { 
0009 this.a = a;