实验六 继承和多态
实验目的
1. 掌握接口的使用方法
2. 掌握子类的继承性、子类对象的创建过程
3. 掌握成员变量的继承与隐藏、方法的继承与重写
实验学时 6学时
实验内容
1. 编写程序为公交车的老人卡、学生卡和普通市民卡提供收费功能。将充值、收费功能提取,定义在一个接口中,然后被这三种卡类实现。最后编写一个测试类,用于测试公交车三类卡的刷卡操作。
package code61;
public interface Buscard { //定义接口Bus card
void recharge();
void charge();
}
package code61;
public class Oldpeople implements Buscard { //实现接口
public void recharge() {
System.out.println("老年卡充值成功!"); //重写接口的充值方法
}
public void charge() {
System.out.println("使用老年卡,扣一元!"); //重写接口的收费方法
}
}
package code61;
public class People implements Buscard { //实现接口
public void recharge() {
System.out.println("普通市民卡充值成功!"); //重写接口充值方法
}
public void charge() {
System.out.println("使用普通市民卡,扣2元!"); //重写接口收费方法
}
}
package code61;
public class Student implements Buscard { //实现接口
public void recharge() {
System.out.println("学生卡充值成功!"); //重写接口充值方法
}
public void charge() {
System.out.println("使用学生卡,扣1.5元!"); //重写接口收费方法
}
}
package code61;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Oldpeople O = new Oldpeople();
O.recharge();
O.charge(); //定义老年卡对象,并调用充值、收费方法
Student S = new Student();
S.recharge();
S.charge(); //定义学生卡对象,并调用充值、收费方法
People P = new People();
P.recharge();
P.charge(); //定义市民卡对象,并调用充值、收费方法
}
}
2.设计四个类、一个接口,类之间的关系如下:
在类App中使用Compute、Circle、Rectangle类,在Compute类中使用Shape接口(Shape对象作为computeArea方法的形式参数),Circle、Rectangle类实现接口Shape,重写area()方法。图中“+”的表示public,“-”的表示private,框图中上面一栏是类或接口的名称,中间一栏是属性,下面一栏是方法。
在App类的main()中:
- 创建一个Compute类对象、一个Circle类对象和一个Rectangle类对象。
- 调用Compute对象的computeArea方法(实际参数为Circle对象)计算圆的面积。
- 调用Compute对象的computeArea方法(实际参数为Rectangle对象)计算矩形面积。
package code62;
public class App {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Compute a = new Compute();
Circle b = new Circle(2);
Rectangle c = new Rectangle(2,2);
System.out.println("圆的面积为:"+a.computArea(b)); //调用Compute对象的computeArea方法,实参为Circle对象
System.out.println("矩形面积为:"+a.computArea(c)); //调用Compute对象的computeArea方法,实参为Rectangle对象
}
}
package code62;
public class Circle implements Shape { //实现接口
private int radius;
public Circle(int radius) {
this.radius=radius;
}
public double area() {
return PI*radius*radius; //重写接口的area方法,求圆的面积
}
}
package code62;
public class Compute {
public double computArea(Shape s) { //Shape对象作为该方法的形式参数
return s.area();
}
}
package code62;
public class Rectangle implements Shape { //实现接口
private int width;
private int height;
public Rectangle(int width,int height) {
this.width=width;
this.height=height;
}
public double area() {
return width*height; //重写接口的area方法,求矩形面积
}
}
package code62;
public interface Shape { //定义接口
double PI=3.14;
double area();
}
3. 普通门和报警门。
(1)定义一个接口Alarm(报警),含有一个报警方法void alarm( );
(2)定义一个类Door(普通门),Door类有一个私有属性name(品牌);有4个公有方法getName、setName、open(开门)、close(关门);open、close方法的功能由自己确定。
(3)定义一个类AlarmDoor(报警门),继承Door类,实现接口Alarm,重写接口中的抽象方法alarm(方法的功能由自己确定)。
(3)编写一个测试类DoorTest,在main方法中,给出多种型号的报警门和普通门,调用开门、关门、报警等动作。
package code63;
public interface Alarm { //定义接口
void alarm();
}
package code63;
public class AlarmDoor extends Door implements Alarm { //继承Door类,实现接口Alarm
public void alarm() {
System.out.println(this.getName()+"嘟嘟嘟!警报响起!"); //重写接口中的抽象方法
}
}
package code63;
public class Door {
private String name; //私有属性name
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
public void open() {
System.out.println(this.name+"门开了!");
}
public void close() {
System.out.println(this.name+"门关了!");
}
}
package code63;
public class DoorTest {
public static void main(String[] args) {
// TODO 自动生成的方法存根
AlarmDoor a1 = new AlarmDoor();
a1.setName("低级报警门!");
a1.open();
a1.alarm(); //创建对象a1,并调用各方法
AlarmDoor a2 = new AlarmDoor();
a2.setName("高级报警门!!!");
a2.open();
a2.close();
a2.alarm(); //创建对象a2,并调用各方法
AlarmDoor a3 = new AlarmDoor();
a3.setName("普通门.");
a3.open();
a3.close(); //创建对象a3,并调用各方法
}
}
4. 设计五个类(测试类、计算机类、手机类、充电器类、U盘类)、一个接口(Usb接口),各类之间的关系如下:
(1)在UsbTest类的main方法中,创建一个Xiaomi手机对象、一个小米CDQ012M充电器对象、一台联想电脑、一个Kingston U盘对象。然后将充电器插入手机充电,将U盘插入计算机。
(2)在Mobile类的InsertUsb方法中,连接Usb。
(3)在Computer类的InsertUsb方法中,连接Usb。
(4)在Charger类的connect方法中,输出“已连接充电器,正在充电...”。
(5)在UDisk类的connect方法中,输出“已连接U盘器,正在读取数据...”。
package code64;
public class Charger implements Usb {
private String brand;
public Charger(String brand) {
this.brand=brand;
}
public void connect() {
System.out.println("已连接充电器"+this.brand+",正在充电..."); //重写接口的connect方法
}
}
package code64;
public class Computer {
private String brand;
public Computer(String brand) {
this.brand=brand;
}
public void insertUsb(Usb device) {
System.out.println(this.brand);
device.connect(); //构造连接方法
}
}
package code64;
public class Moblie {
private String brand;
public void Moblie(String brand) {
this.brand=brand;
}
public void insertUsb(Usb device) {
System.out.println(this.brand);
device.connect(); //构造连接方法
}
}
package code64;
public class UDisk implements Usb {
private String brand;
public UDisk(String brand) {
this.brand=brand;
}
public void connect() {
System.out.println("已连接U盘器"+this.brand+",正在读取数据..."); //重写接口的connect方法
}
}
package code64;
public interface Usb { //定义接口
void connect();
}
package code64;
public class UsbTest {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Moblie a = new Moblie();
a.Moblie("Xiaomi"); //创建手机对象
Charger b = new Charger("小米CDQ012M"); //创建充电器对象
Computer c = new Computer("联想"); //创建电脑对象
UDisk d = new UDisk("Kingston"); //创建U盘对象
a.insertUsb(b); //充电器插入手机
c.insertUsb(d); //U盘插入计算机
}
}
5. 设计一个武器系统,要求如下:
(1)定义一个弹药类Bullet,有一个弹药名称属性name。设计一个构造方法及set、get方法。
(2)定义一个可装载弹药的接口Loadable,该接口有一个装载的抽象方法load()。
(3)定义一个可发射弹药的接口Launchable,该接口有一个发射的抽象方法launch()。
(4)定义一个武器类Weapon,既可以装弹,也可以发射。
武器类有一个属性name(武器名称)、可使用的弹药bullet(Bullet对象)以及对应的get、set方法。
重写load方法,在方法中输出装载的弹药。
重写launch方法,在方法中输出发射的弹药。
(4)定义3个普通武器类:Tank、Flighter、WarShip都继承武器类Weapon。 每个普通武器类都有一个带一个参数name的构造方法,在构造方法中创建弹药对象。
坦克Tank使用的弹药是炮弹,战斗机Flighter使用的弹药是导弹,舰艇WarShip使用的弹药是鱼雷。
(5)定义一个类Army,代表一支军队,包括:。
1) 属性:ArrayList<Weapon> weapon用来存放军队装备的各种武器,自己查找集合类ArrayList的用法和泛型的知识点;
2) 获取军队的拥有的武器数量方法getNum;
3)添置武器的方法addWeapon
4) 让所有武器都装载弹药的方法loadAll;
5)让所有武器都发起攻击的方法luanchAll。
(6)编写一个测试类,在main方法中:
1)建立一支强大的军队;
2)添置各种型号武器,包括坦克、战机、舰艇。
3)输出军队拥有的武器数量;
4)让所有的武器都装上弹药;
5)让所有的武器都发射。
package code65;
import java.util.ArrayList;
public class Army {
ArrayList<Weapon> weapon;
public Army() {
weapon = new ArrayList<Weapon>(); //存放军队装备的各种武器
}
public int getNum() {
return weapon.size(); //获取军队的拥有的武器数量
}
public void addWeapon(Weapon weapon) {
this.weapon.add(weapon); //添置武器
}
public void loadAll() {
System.out.println("所有武器准备装弹药...");
int a=1;
for(Weapon weapon:weapon) {
System.out.print(a+":"+weapon.getName());
weapon.load();
a++; //让所有武器都装载弹药
}
}
public void luanchAll() {
System.out.println("所有武器准备战斗...");
int a=1;
for(Weapon weapon:weapon) {
System.out.print(a+":"+weapon.getName());
weapon.launch();
a++; //让所有武器都发射弹药
}
}
}
package code65;
public class Bullet {
private String name;
public Bullet(String name) { //构造方法
this.name=name;
}
public void setName(String name) {
this.name=name;
}
public String getName() {
return name;
}
}
package code65;
public class Flighter extends Weapon { //继承武器类
public Flighter(String name) {
setName(name);
Bullet bullet = new Bullet("导弹"); //创建导弹对象
setBullet(bullet);
}
}
package code65;
public interface Launchable { //定义一个可发射弹药的接口
void launch();
}
package code65;
public interface Loadable { //定义一个可装载弹药的接口
void load();
}
package code65;
public class Tank extends Weapon { //继承武器类
public Tank(String name) {
setName(name);
Bullet bullet = new Bullet("炮弹"); //创建炮弹对象
setBullet(bullet);
}
}
package code65;
public class WarShip extends Weapon { //继承武器类
public WarShip(String name) {
setName(name);
Bullet bullet = new Bullet("鱼雷"); //创建鱼雷对象
setBullet(bullet);
}
}
package code65;
public class Weapon implements Loadable,Launchable { //实现两接口
private String name;
private Bullet bullet;
public String getName() {
return name;
}
public void setName(String name) {
this.name=name;
}
public Bullet getBullet() {
return bullet;
}
public void setBullet(Bullet bullet) {
this.bullet=bullet;
}
public void load() {
System.out.println("装载"+this.bullet.getName()); //重写接口的装载方法
}
public void launch() {
System.out.println("发射"+this.bullet.getName()); //重写接口的发射方法
}
}
package code65;
public class Test {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Tank a1 = new Tank("99坦克 ");
Flighter a2 = new Flighter("歼20 ");
WarShip a3 = new WarShip("武汉舰 ");
WarShip a4 = new WarShip("芜湖舰 ");
Flighter a5 = new Flighter("歼31 ");
Flighter a6 = new Flighter("F35 "); //建立军队
Army a = new Army();
a.addWeapon(a1);
a.addWeapon(a2);
a.addWeapon(a3);
a.addWeapon(a4);
a.addWeapon(a5);
a.addWeapon(a6); //添置各种武器
System.out.println("军队装备的武器数量:"+a.getNum());
a.loadAll(); //让所有武器装上弹药
a.luanchAll(); //让所有武器都发射
}
}
6. 设计五个类,类之间的关系如下
在类App中使用Paint、Rectangle、Circle、Rabit类,在paint类中使用AsciiArt抽象类(AsciiArt对象作为setArt方法的参数),Rectangle、Circle、Rabit类继承抽象类AsciiArt,并重写draw()方法。
具体设计步骤:
- App类的main( )
1)创建一个Paint对象paint
2)显示作品列表
========作品列表=======
- 矩形
- 圆
- 小兔子
======================
请选择:
3) 根据选择,显示不同的作品
① 画矩形
a.创建一个Rectangle对象rect。
b.调用paint的setArt方法,将rect设置为paint对象要显示的作品。
c.调用对象paint的draw方法显示作品。
②画圆
a.创建一个Circle对象c。
b.调用paint的setArt方法,将c设置为paint对象要显示的作品。
c.调用对象paint的draw方法显示作品。
③画小兔子
a.创建一个Rabit对象rabit。
b.调用paint的setArt方法,将rabit设置为paint对象要显示的作品。
c.调用对象paint的draw方法显示作品。
- Paint类中的draw( )
①显示作品名、作者。
②调用成员变量art的draw方法显示作品。
- Rectangle类中的draw( )
输出width行height列个“*”。
- Circle类中的draw( )
输出用“*”组成的圆。
- Rabit类中的draw( )
输出可爱的小兔。
package code66;
import java.util.Scanner;
public class App {
public static void main(String[] args) {
// TODO 自动生成的方法存根
Scanner in=new Scanner(System.in);
System.out.println("========作品列表=======");
System.out.println("1.矩形");
System.out.println("2.圆");
System.out.println("3.小兔子");
System.out.println("======================");
System.out.println("请选择:");
int select=in.nextInt();
Paint paint = new Paint();
switch(select){ //根据选择,显示不同作品
case 1:
Rectangle rect = new Rectangle("矩形","张三",3,8);
paint.setArt(rect); //调用方法,将rect设置为paint对象要显示的作品
paint.draw(); //调用draw方法
break;
case 2:
Circle c = new Circle("圆形","小丫",4);
paint.setArt(c); //调用方法,将c设置为paint对象要显示的作品
paint.draw(); //调用draw方法
break;
case 3:
Rabit rabit = new Rabit("兔子","李四");
paint.setArt(rabit); //调用方法,将rabit设置为paint对象要显示的作品
paint.draw(); 调用draw方法
break;
}
}
}
package code66;
public abstract class AssciiArt { //定义一个抽象类
private String title; //作品名
private String author; //作者名
public AssciiArt(String title,String author) {
this.title=title;
this.author=author;
}
abstract void draw(); //抽象画图方法
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title=title;
}
public String getAuthor() {
return author;
}
public void setAuthor(String author) {
this.author=author;
}
}
package code66;
public class Circle extends AssciiArt { //继承AssciiArt类
private int radius;
public Circle(String title,String author,int radius) {
super(title,author); //访问父类中被覆盖的成员
this.radius=radius;
}
public void draw() { //重写画图方法
int d=2*radius;
for(int y=0;y<=d;y++) {
for(int x=0;x<=d;x++) {
if((x-radius)*(x-radius)+(y-radius)*(y-radius)<=radius*radius)
System.out.print("**");
else
System.out.print(" ");
}
System.out.println(); //输出用"*"组成的圆
}
}
}
package code66;
public class Paint {
private AssciiArt art;
public void setArt(AssciiArt art) { //AsciiArt对象作为setArt方法的参数
this.art=art;
}
public void draw() {
System.out.println("作品:"+this.art.getTitle());
System.out.println("作者:"+this.art.getAuthor());
this.art.draw(); //调用art的draw方法显示作品
}
}
package code66;
public class Rabit extends AssciiArt { //继承AssciiArt类
public Rabit(String title,String author) {
super(title,author); //访问父类中被覆盖的成员
}
public void draw() { //重写画图方法
System.out.println("/)/)");
System.out.println("(- -) )o");
System.out.println(" || ||"); //画出小兔子
}
}
package code66;
public class Rectangle extends AssciiArt { //继承AssciiArt类
private int width;
private int height;
public Rectangle(String title,String author,int width,int height) {
super(title,author); //访问父类中被覆盖的成员
this.width=width;
this.height=height;
}
public void draw() { //重写画图方法
for(int a=0;a<width;a++) {
for(int b=0;b<height;b++) {
System.out.print("*"); //输出width行height列个"*"组成的矩形
}
System.out.println();
}
}
}
实验小结
- 类的继承是实现代码复用最有效的方法;
- Java只支持单继承,即只能有一个父类,但类之间的继承可以传递;
- 继承格式:class 子类名 extends 父类名;
- 关键字super可以用来在子类中访问父类中被覆盖的成员;
- 关键字abstract修饰的类为抽象类,其更多是作为其他类的父类,其中的抽象方法必须在子类中具体实现;
- 接口定义格式:【修饰符】interface接口名;
- 接口中的所有方法都是抽象的,必须在实现该接口的子类中重写所有的抽象方法;
- 接口实现格式:class 类名 implements 接口名;
- 被实现的接口可以有多个,之间有逗号隔开;
- 另外还要去掌握ArrayList的使用方法。