第四章补充案例
案例4-1 类的继承
一、案例描述
1、考核知识点
编号:00104001
名称:类的继承
2、练习目标
了解类继承的意义和作用
掌握如何实现类的继承
3、需求分析
在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。
为了让初学者熟悉类的继承,本案例将演示类的继承并编写测试类验证子类是否拥有父类的可继承成员。
4、设计思路(实现原理)
1)设计两个类Student和Teacher
2)抽取两个类共同的内容(如:吃饭、睡觉)封装到一个类Person中,各自特有的部分保留在各自类中。
3)让学生类继承Person类,老师类也继承Person。
4)编写测试类Example01,测试Student类和Teacher是否继承了Person类的成员。
二、案例实现
1、抽取父类Person,实现继承关系,代码如下:
class Person {
String name;//姓名
// 吃饭的功能
void eat() {
System.out.println("吃饭 ");
}
// 睡觉的功能
void sleep() {
System.out.println("睡觉");
}
}
class Student extends Person {
1
2
// 学号 int sid;
}
class Teacher extends Person { // 工号 int tid; // 教课的功能 void teach() { System.out.println("老师教课"); }
}
2、定义测试类Example01,代码如下:
public class Example01{ public static void main(String[] args) { Student s = new Student(); s.eat(); s.sleep();
System.out.println("----"); Teacher t = new Teacher(); t.eat(); t.sleep(); t.teach();
}
}
运行结果如图4-1所示。
图4-1 运行结果
三、案例总结
1、在Java 中,多个类可以继承一个父类,但是一个类不能直接继承多个类,一个类只能有一个直接父类。
2、父类是由子类不断抽取而来的,不断地抽取就形成了体系结构,这个结构称为继承体系结构。
3、子类在继承父类的时候,会自动拥有父类所有的成员。
4、继承的好处是划分了类的层次性,实现了代码重用、扩展了程序功能。
案例4-2 方法的重写
一、案例描述
1、考核知识点
编号:00104002
名称:方法的重写
2、练习目标
了解方法重写的意义和作用
掌握如何进行方法重写
3、需求分析
在继承关系中,子类会自动继承父类中定义的方法,但有时在子类中需要对继承的方法进行一些修改,即对父类的方法进行重写。为了让初学者掌握方法的重写,本案例将编写一个类NewPhone,该类继承Phone类并对Phone类的call()方法进行重写。
4、设计思路(实现原理)
1)定义一个类Phone,编写方法call(),表示打电话功能
2)定义一个Phone的子类NewPhone,重写父类call()方法,让它除了打电话功能外还具有开启语言和关闭语言功能。
3)编写一个测试类Example02,分别调用重写前和重写后的call()方法
二、案例实现
1、定义Phone及其子类NewPhone,子类对父类中的call()方法重写,代码如下:
class Phone {
void call() {
System.out.println("打电话");
}
}
class NewPhone extends Phone {
void call() {
System.out.println("开启语音");
super.call();
System.out.println("关闭语音");
}
}
2、定义测试类Example02,代码如下:
public class Example02{
public static void main(String[] args) {
System.out.println("--重写前--");
Phone phone = new Phone();
3
4
phone.call();
System.out.println("--重写后--"); Phone newPhone = new NewPhone(); newPhone.call();
}
}
运行结果如图4-2所示。
图4-2 运行结果
三、案例总结
1、子类中需要对继承自父类的方法进行一些修改,这时就用到方法重写。
2、在子类中重写的方法需要和父类被重写的方法具有相同的方法名、参数列表以及返回值类型。
3、子类方法的访问修饰权限不能小于父类的。
4、重写的主要优点是能够定义子类特有的特征。
案例4-3 super 访问父类成员变量 一、案例描述
1、 考核知识点 编号:00104003 名称:super 关键字
2、 练习目标
掌握使用super 关键字访问父类成员变量
3、 需求分析
子类可以继承父类的非私有成员变量,如果在子类中修改了继承自父类的成员变量的值,再想要访问父类的该成员变量时,可以通过super.成员变量来实现。为了让初学者熟悉super 关键字的用法,本案例将分别设计Fu 类及其子类Zi ,并在Zi 类的方法中使用super 关键字访问Fu 类的成员变量。 4、 设计思路(实现原理)
1)编写一个Fu 类,在类中定义无参构造和一个初始值为20的num 成员变量。
2)Zi 类继承Fu 类,在子类中对num 值进行了修改,同时在子类中定义无参构造和一个无返回值的method()方法,method()方法中使用super 关键字调用了Fu 类的num 成员变量。 3)定义测试类Example03。
5
二、案例实现
1、编写Fu 类及其子类Zi ,在Zi 类中使用super 关键字调用Fu 类成员变量,代码如下
class Fu { Fu() {} int num = 20;
}
class Zi extends Fu {
Zi() {}
int num = 30;// 修改num 的值 void method() { System.out.println("method"); // super 关键字调用父类成员变量
System.out.println("Fu 类中num 值为:" + super.num); System.out.println("Zi 类中num 值为:" + num); }
}
2、定义测试类Example03,代码如下:
class Example03{ public static void main(String[] args) { Zi z = new Zi(); z.method();
}
}
运行结果如图4-3所示。
图4-3 运行结果
三、案例总结
1、使用super 关键字调用父类的成员方法。具体格式如下:
super.成员变量
2、被调用的父类成员变量,必须是非private 的。
案例4-4 super访问父类成员方法
一、案例描述
1、考核知识点
编号:00104003
名称:super关键字
2、练习目标
掌握使用super关键字访问父类成员方法
3、需求分析
子类重写父类的方法后,子类对象将无法访问父类被重写的方法,为了解决这个问题,在Java中专门提供了一个super关键字用于访问父类的成员。为了让初学者熟悉super关键字的用法,本案例将分别设计Fu类及其子类Zi,在Zi类的方法中使用super关键字访问Fu类的成员方法。
4、设计思路(实现原理)
1)编写一个Fu类,在类中定义无参构造和一个无返回值的show()方法。
2)Zi类继承Fu类,子类中定义无参构造和一个无返回值的method()方法,method()方法中使用super关键字调用了Fu类的show()方法。
3)定义测试类Example04。
二、案例实现
1、编写Fu类及其子类Zi,在Zi类中使用super关键字调用Fu类成员方法,代码如下:
class Fu {
Fu() {}
void show() {
System.out.println("Fu show");
}
}
class Zi extends Fu {
Zi() {}
void method() {
System.out.println("Zi method");
// super关键字调用父类成员方法
super.show();
}
}
2、定义测试类Example04,代码如下:
class Example04{
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
6
运行结果如图4-4所示。
图4-4运行结果
三、案例总结
1、使用super关键字调用父类的成员方法。具体格式如下:
super.成员方法([参数1,参数2…])
2、被调用的父类成员方法,必须是非private的。
案例4-5 super访问父类构造方法
一、案例描述
1、考核知识点
编号:00104003
名称:super关键字
2、练习目标
掌握如何在子类构造方法中使用super关键字访问父类构造方法
3、需求分析
在子类的构造方法中一定会调用父类的某个构造方法,如果想指定调用类父类中的哪个构造方法,可以使用super关键字来实现。为了让初学者掌握super关键字的用法,本案例将分别设计Fu类及其子类Zi,在Zi类的构造方法中使用super关键字访问Fu类的构造方法。
4、设计思路(实现原理)
1)编写一个Fu类,在类中定义无参构造。
2)Zi类继承Fu类,子类中也定义无参构造方法,在构造方法中使用super关键字调用Fu类的构造方法。
3)定义测试类Example05。
二、案例实现
1、编写Fu类及其子类Zi,在Zi类构造中使用super关键字调用Fu类构造方法,代码如下:
class Fu {
Fu() {
System.out.println("Fu类构造方法!");
}
7
8
class Zi extends Fu { Zi() {
super();//在子类构造中调用父类构造 System.out.println("Zi 类构造方法!"); }
}
2、定义测试类
Example05,代码如下:
public class Example05{ public static void main(String[] args) { Zi zi = new Zi();
}
}
运行结果如图4-5所示。
图4-5 运行结果
三、案例总结
1、通过super 调用父类构造方法的代码必须位于子类构造方法的第一行,并且只能出现一次。
2、在子类的构造方法中通过super 指定调用父类的哪个构造方法,如果没有指定,在实例化子类对象时,会自动调用父类无参的构造方法。
3、被调用的父类构造方法,必须是非private 的。
案例4-6 final 修饰类 一、案例描述
1、 考核知识点
编号:00104004 名称:final 关键字
2、 练习目标
了解final 关键字修饰类的特点 掌握final 关键字修饰类的用法
3、 需求分析
Java 中的类被final 关键字修饰后,该类将不可以被继承,也就是不能够派生子类。为了让初学者熟悉final 关键字修饰类的用法,本案例将分别设计两个类,一个是使用final 关键字修饰的Fu 类,另一个是继承Fu 类的Zi 类,验证final 关键字修饰的类是否能被继承。
9
4、 设计思路(实现原理)
1)编写一个final 关键字修饰的Fu 类,类体可以为空 2)编写Zi 类,Zi 类继承于Fu 类,类体可以为空 3)定义测试类Example06。
二、案例实现
1、编写final 修饰的Fu 类,Zi 类继承Fu 类,代码如下:
final class Fu { // 类体为空代码
}
//Zi 类继承final 修饰的
Fu 类 class Zi extends Fu { // 类体为空代码 }
2、定义测试类Example06,代码如下:
public class Example06{ public static void main(String[] args) { Zi zi = new Zi();
}
}
运行结果如图4-6所示。
图4-6 运行结果
三、案例总结
在Java 中,被final 关键字修饰的类为最终类,不能被其它类继承。
案例4-7 final 修饰方法 一、案例描述
1、 考核知识点 编号:00104004 名称:final 关键字
2、 练习目标
10
掌握使用final 关键字修饰方法
3、 需求分析
子类可以继承父类的成员方法,并在必要时对方法进行重写,增加了方法的扩展的同时也打破了方法的封装,如果我们希望父类中的某些方法不能被重写,这时就可以使用final 关键字来修饰。为了让初学者掌握使用final 关键字修饰方法,本案例将分别设计两个类,一个是Fu 类,其中定义了final 修饰的show()方法,另一个是继承Fu 类的Zi 类,在Zi 类中对show()方法进行重写。 4、 设计思路(实现原理)
1)编写一个Fu 类,类中定义final 修饰的show()方法。
2)编写Zi 类,Zi 类继承于Fu 类,在Zi 类中对show()方法进行重写 3)定义测试类Example07,创建Zi 类对象,并调用Zi 类show()方法。
二、案例实现
1、编写Fu 类及其子类Zi 类,在Zi 类中对show()方法重写,代码如下:
class Fu { //final 关键字修饰的方法 public final void show() { System.out.println("这是绝密资源");
}
}
class Zi extends Fu { //重写父类中final 修饰的方法 public void show() { System.out.println("这是一堆垃圾,给处理了"); }
}
2、定义测试类Example07,代码如下:
public class Example07{ public static void main(String[] args) { Zi z = new Zi(); z.show();
}
}
运行结果如图4-7所示。
图4-7 运行结果
11
当一个类的方法被final 关键字修饰后,这个类的子类将不能重写该方法。
案例4-8 final 修饰局部变量 一、案例描述
1、 考核知识点 编号:00104004 名称:final 关键字
2、 练习目标
掌握使用final 关键字修饰局部变量
3、 需求分析
Java 中被final 修饰的变量为常量,它只能被赋值一次,也就是说final 修饰的变量一旦被赋值,其值不能改变。为了让初学者掌握使用final 关键字修饰局部变量,本案例将在类的方法中定义一个final 修饰的局部变量,并试着对该变量重新赋值。
4、 设计思路(实现原理)
1)编写一个Example08类,类中定义类一个final 修饰的局部变量age ,为其赋初始值为18。 2)为age 重新赋值为20。
二、案例实现
1、编写类Example08,代码如下
public class Example08{ public static void main(String[] args) { final int age = 18; // 第一次可以赋值 age = 20; // 再次赋值会报错
}
}
编译错误,如图4-8所示。
图4-8 错误提示
final修饰的变量表示常量,一经定义就不能重新赋值。
案例4-9 final修饰成员变量
一、案例描述
1、考核知识点
编号:00104004
名称:final关键字
2、练习目标
掌握使用final关键字修饰成员变量
3、需求分析
在Java中,final修饰的变量表示常量,一经定义就不能重新赋值。为了让初学者熟悉final修饰变量的情况,本案例将使用final关键字修饰成员变量,观察其是否能够再次赋值。
4、设计思路(实现原理)
1)编写一个Fu类,父类中定义一个变量X,并用final关键字修饰变量。
2)编写Zi类,Zi类继承于Fu类,在子类中对常量再赋新值。
3)定义测试类Example09,观察运行结果。
二、案例实现
1、编写Fu类及其子类Zi类,在Zi类中对X再赋值,代码如下:
class Fu {
//final修饰的变量,也就是常量
public final int X = 10;
}
class Zi extends Fu {
X = 20;//在子类中对常量再赋新值
public void method() {
System.out.println(X);
}
}
2、定义测试类Example09,代码如下:
public class Example09{
public static void main(String[] args) {
Zi z = new Zi();
z.method();
}
12
}
编译错误,结果如图4-9所示。
图4-9错误提示
三、案例总结
在本案例中Zi类中对变量X再次赋值,运行结果报错。这是因为Java中被final修饰的变量为常量,它只能被赋值一次,也就是说final修饰的变量一旦被赋值,其值不能改变。如果再次对该变量进行赋值,则程序会在编译时报错。
案例4-10 接口的实现
一、案例描述
1、考核知识点
编号:00104006
名称:接口
2、练习目标
掌握如何实现接口
3、需求分析
由于接口中的方法都是抽象方法,因此不能通过实例化对象的方式来调用接口中的方法。此时需要定义一个类,并使用implements关键字实现接口中所有的方法。为了上初学者掌握如何实现接口,本案例将设计一个类,使用关键字implements实现Inter接口中的方法。
4、设计思路(实现原理)
1)设计名为Inter的接口,接口中定义一个初始值为20的num常量和method()抽象方法。
2)编写Inter接口的实现类InterImpl,使用implements关键字实现接口中的方法。
3)编写测试类Example10,测试类中对接口的实现类进行实例化,并调用接口中的方法。
二、案例实现
1、编写接口Inter,InterImpl类使用implements实现了接口,代码如下:
//定义一个接口
interface Inter {
int num = 20;
void method();
}
13
14
// 使用implements 关键字实现接口 class InterImpl implements Inter { void show() { System.out.println(num);
}
public void method() { System.out.println("InterImpl method"); }
}
2、定义测试类Example10,代码如下:
class Example10{ public static void main(String[] args) { //通过实现类实例化
InterImpl ii = new InterImpl(); ii.show(); ii.method();
}
}
运行结果如图4-10所示。
图4-10 运行结果
三、案例总结
1、接口使用interface 关键字来定义。
2、接口没有构造方法,接口中的变量缺省都是使用public static final 修饰的,即全局常量,接口中的方法都是public abstract 修饰的,即抽象方法。
3、定义一个类,并使用implements 关键字实现接口中的方法,一个类可以实现多个接口。
4、由于接口中的方法都是抽象方法,因此不能直接通过实例化对象的方式来调用接口中的方法,需要在类实现接口后借助类来间接实例化。
案例4-11 接口的继承 一、案例描述
1、 考核知识点
编 号:00104007
名 称:接口的继承与多实现
2、练习目标
掌握接口继承的方式及其特点
3、需求分析
在程序中,可以定义一个接口使用extends关键字去继承另一个接口。为了加深初学者对结果的理解,本案例将演示接口与接口、类与接口的继承和实现关系。
4、设计思路(实现原理)
1)设计接口Phone代表传统手机,在接口中定义receiveMessages()和call()抽象方法。
2)设计接口SmartPhone代表智能手机,在接口中定义faceTime()方法,并使用extends关键字继承Phone接口,使其具有Phone接口的所有功能。
3)设计类MIPhone表示小米手机,类中定义useMIUI()方法,并实现SmartPhone接口的所有方法。
4)编写测试类Example11,测试类中对MIPhone进行实例化,并访问小米手机具有的各种功能。
二、案例实现
1、编写接口Phone和SmartPhone、类MIPhone。代码如下:
interface Phone {
void receiveMessages();
void call();
}
interface SmartPhone extends Phone {
void faceTime();
}
class MIPhone implements SmartPhone {
public void receiveMessages() {
System.out.println("接收短息");
}
public void call() {
System.out.println("语音通话");
}
public void faceTime() {
System.out.println("视频通话");
}
public void useMIUI() {
System.out.println("使用MIUI");
}
}
2、定义测试类Example11,代码如下:
public class Example11 {
public static void main(String[] args) {
MIPhone miPhone = new MIPhone();
miPhone.receiveMessages();
miPhone.call();
miPhone.faceTime();
15
16
https://www.wendangku.net/doc/b818645470.html,eMIUI();
}
}
运行结果如图4-11所示。
图4-11 运行结果
三、案例总结
接口与接口之间的继承关系,可以是单继承,也可以是多继承;一个接口可以通过extends 关键字继承多个接口,接口之间用逗号隔开。
案例4-12 Object 类 一、案例描述
1、 考核知识点
编 号:00104008 名 称:Object 类
2、 练习目标
了解什么是Object 类
掌握Object 类中常用方法的使用
3、 需求分析
在JDK 中提供了一个Object 类,它是所有类的父类,即每个类都直接或间接继承自该类。Object 类自身的equals()方法比较的是内存地址值,相当于“==”,但是在实际开发中我们很少比较两个对象的地址值,这时候常常就需要根据自身需求来重写equals()方法。为了方便初学者学习Object 类,本案例将演示如何重写equals()方法。
4、 设计思路(实现原理)
1)设计Student 类,定义sid 变量表示学号,重写equals()方法,判断进行比较的两个学生对象学号是否相同,相同即为同一个学生,否则不是。
2)编写测试类Example12,创建两个Student 的对象Lily 和Lucy ,并分别调用setter 方法为学号赋值,最后通过打印语句,输出这两个对象通过“==”和重写后的equals()方法比较后的结果。
二、案例实现
1、编写Student 类,重写equals()方法。代码如下:
class Student {
Student() {}
17
// 学号
private int sid;
public void setSid(int sid) { this.sid = sid;
}
public int getSid() { return sid; }
// 我们的需求是学号相同的人就是同一个人. public boolean equals(Object obj) { // 判断是否为当前对象
if (this == obj) { return true; }
// 为了呈现的健壮性,加入类型判断 if (!(obj instanceof Student)) { return false; }
Student s = (Student) obj; return (this.sid == s.sid);
}
}
2、定义测试类Example12,为学号赋值,并打印使用“==”和重写equals()方法的比较结果,代码如下:
public class Example12 { public static void main(String[] args) { Student Lily = new Student(); Lily.setSid(200);
Student Lucy = new Student(); Lucy.setSid(200);
System.out.println("Lily == Lucy"+"\t\t"+(Lily == Lucy)); System.out.println("Lily.equals(Lucy)"+"\t"+Lily.equals(Lucy));
}
}
运行结果如图4-12所示。
图4-12 运行结果
三、案例总结
1、Object类是Java中所有类的父类,每个类都直接或间接继承自该类。
2、Object类中的equals()方法比较的是内存地址值,和“==”比较结果一致。底层代码如下:
public boolean equals(Object obj) {
return (this == obj);
}
实际开发中很少比较内存地址值,所以我们常常会根据自身需求重写equals()方法。
案例4-13 多态的作用
一、案例描述
1、考核知识点
编号:00104009
名称:多态
2、练习目标
了解多态的概念、多态的好处和弊端
掌握如何实现多态
3、需求分析
在Java中为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象,根据被引用子类对象特征的不同,得到不同的运行结果。多态提高代码了的扩展性和可维护性。为了帮助初学者掌握如何实现多态,本案例将实现一个多态程序来演示如何实现多态。
4、设计思路(实现原理)
1)编写Animal接口,接口中定义sleep()方法。
2)Cat类实现Animal接口的方法,并定义另一个方法catchMouse()
3)编写测试类Example13,使Cat对象指向父类Animal的引用,并通过该引用调用sleep()方法。
二、案例实现
1、编写Animal接口及其实现类Cat。代码如下:
interface Animal {
void sleep();
}
class Cat implements Animal {
void catchMouse() {
System.out.println("抓老鼠");
}
public void sleep() {
System.out.println("睡觉");
}
18
19
}
2、定义测试类Example13,Cat 对象指向Animal 引用,并使用父类Animal 引用调用sleep()方法。代码如下:
public class Example13 { public static void main(String[] args) {
// 多态
Animal animal = new Cat(); animal.sleep();
}
}
运行结果如图4-13所示。
图4-13 运行结果
三、案例总结
1、多态是指对象在不同时刻表现出来的不同状态,在Java 中,允许使用一个父类类型的变量来引用一个子类类型的对象。
2、多态的前提:
(1) 要有继承关系。 (2) 要有方法重写。
(3) 要有父类引用指向子类对象。
3、多态的好处是提高代码的扩展性和可维护性。
4、多态的弊端是父类或者接口只能调用自己具备的成员,不能访问子类特有的成员。
案例4-14 对象的类型转换 一、案例描述
1、 考核知识点
编 号:00104010
名 称:对象的类型转换 2、 练习目标
掌握如何实现对象的类型转换
3、 需求分析
在多态的学习中,涉及到将子类对象当做父类类型使用的情况,这时进行强制类型转换可能会出现出错。为了让初学者熟悉对象的类型转换,本案例将演示一个子类与父类之间类型转换过程中出现的错误。
编写一个接口Animal ,接口中定义sleep()方法,编写两个类Cat 和Pig 分别实现接口,再编写一
20
个测试类Example14实现对象的类型转换。
4、 设计思路(实现原理)
1)编写Animal 接口,接口中定义sleep()方法。 2)Cat 类和Pig 类分别实现Animal 接口的方法 3)编写测试类Example14对对象的类型进行转换,使Cat 向上转型为Animal 类型,然后再让Animal 类型转换为Pig 类型。
二、案例实现
1、编写Animal 接口及其实现类Cat 。代码如下:
interface Animal { void sleep();
}
class Cat implements Animal { public void sleep() { System.out.println("猫晚上睡觉"); }
}
class Pig implements Animal { public void sleep() {
System.out.println("猪整天睡觉"); }
}
2、定义测试类Example14,Cat 对象指向Animal 引用,并使用父类Animal 引用调用sleep()方法。代码如下:
public class Example14 { public static void main(String[] args) { Animal animal = new Cat(); Pig pig = (Pig) animal; pig.sleep();
}
}
运行结果如图4-14所示。
图4-14 错误提示
三、案例总结
1、向下类型转换时,需要注意被转换对象的真实类型是否和需要转换的对象类型相同,否则容易报