多态和继承编程练习
一、不同国籍身高体重问题
编写程序模拟中国人、美国人是人;北京人是中国人。除主类外,程序中还有4个类:People、ChinaPeople、AmericanPeople和BeijingPeople类。要求如下:
(1) People类有权限是protected的double型成员变量height和weight,以及public void speakHello()、public void averageHeight()和public void averageWeight()方法。
(2) ChinaPeople类是People的子类,新增了public void chinaGongfu()方法。要求ChinaPeople重写父类的public void speakHello()、public void averageHeight()和public void averageWeight()方法。
(3)AmericanPeople类是People的子类,新增public void americanBoxing()方法。要求AmericanPeople重写父类的public void speakHello()、public void averageHeight()和public void averageWeight()方法。
(4)BeijingPeople类是ChinaPeople的子类,新增public void beijingOpera()方法。要求ChinaPeople重写父类的public void speakHello()、public void averageHeight()和public void averageWeight()方法。
People、ChinaPeople、AmericanPeople和BeijingPeople类的UML图如下图所示:
People类:
public class People {
protected double height;
protected double weight;
public void speakHello(){
System.out.printf("people say hello"+"\n");
}
public void averageHeight(){
System.out.printf("普通人平均身高:"+this.height+"\n");
}
public void averageWeight(){
System.out.printf("普通人平均体重:"+this.weight+"\n");
}
}
ChinaPeople类:
public class ChinaPeople extends People {
//新增方法
public void chinaGongfu(){
System.out.printf("chinaGongfu yyds!"+"\n");
}
//重写方法
public void speakHello(){
System.out.printf("chinese people say ‘nihao’."+"\n");
}
//重写方法
public void averageHeight(){
System.out.printf("中国人平均身高:"+this.height+"\n");
}
//重写方法
public void averageWeight(){
System.out.printf("中国人平均体重:"+this.weight+"\n");
}
}
AmericanPeople类:
public class AmericanPeople extends People {
//新增方法
public void americanBoxing(){
System.out.printf("American Boxing"+"\n");
}
//重写方法
public void speakHello(){
System.out.printf("American people say 'hello'."+"\n");
}
//重写方法
public void averageHeight(){
System.out.printf("美国人平均身高:"+this.height+"\n");
}
//重写方法
public void averageWeight(){
System.out.printf("美国人平均体重:"+this.weight+"\n");
}
}
BeijingPeople类:
public class BeijingPeople extends ChinaPeople {
//新增方法
public void beijingOpera(){
System.out.printf("Beijing Opera"+"\n");
}
//重写方法
public void speakHello(){
System.out.printf("北京人打招呼说:‘吃了吗您呐’"+"\n");
}
//重写方法
public void averageHeight(){
System.out.printf("北京人平均身高:"+this.height+"\n");
}
//重写方法
public void averageWeight(){
System.out.printf("北京人平均体重:"+this.weight+"\n");
}
}
Text测试主类:
public class Text {
public static void main(String args[]){
People people1=new People();
people1.height=170;
people1.weight=60;
people1.speakHello();
people1.averageHeight();
people1.averageWeight();
ChinaPeople chinapeople1=new ChinaPeople();
chinapeople1.height=165;
chinapeople1.weight=55;
chinapeople1.speakHello();
chinapeople1.chinaGongfu();
chinapeople1.averageHeight();
chinapeople1.averageWeight();
BeijingPeople beijingpeople1=new BeijingPeople();
beijingpeople1.height=165;
beijingpeople1.weight=55;
beijingpeople1.speakHello();
beijingpeople1.beijingOpera();
beijingpeople1.averageHeight();
beijingpeople1.averageWeight();
AmericanPeople americanPeople1=new AmericanPeople();
americanPeople1.height=165;
americanPeople1.weight=55;
americanPeople1.speakHello();
americanPeople1.americanBoxing();
americanPeople1.averageHeight();
americanPeople1.averageWeight();
}
}
运行结果:
二、银行存款利息问题
假设银行Bank已经有了按整年year计算利息的一般方法,其中year只能取正整数。比如按整年计算的方法:
double computerInterest() {
interest=year*0.035*savedMoney;
return interest;
}
建设银行ConstructionBank是Bank的子类,准备隐藏继承的成员变量year,并重写计算利息的方法,即自己声明一个double型的year变量,比如,当year取值为5.216时,表示要计算5年零216天的利息,但希望首先按银行Bank的方法computerInterest()计算出5整年的利息,然后再自己计算216天的利息。那么,建设银行就必须把5.216的整数部分赋给隐藏的year,并让super调用隐藏的、按整年计算利息的方法。
要求:ConstructionBank和BankOfQingdao类是Bank类的子类,ConstructionBank和BankOfQingdao都使用super调用隐藏的成员变量和方法。
ConstructionBank、BankOfQingdao和Bank类的UML图如下所示:
注:整年利率:0.035 ,建设银行按天计算利率:0.0001,青岛银行按天计算利率:0.00015
(1)计算5万元存5年零216天,在建设银行和青岛银行存的话,利息差额是多少?
(2)参照建设银行或青岛银行,再编写一个商业银行,让程序输出8000元存在商业银行8年零236天的利息。商业银行按天计算利率是0.00012。
Bank类:
public class Bank {
int savedMoney;
int year;
double interest;
double computerInterest() {
this.interest = this.year*0.035*this.savedMoney;
return interest;
}
}
ConstructionBank类:
import java.lang.Math;
public class ConstructionBank extends Bank {
double year;
public double computerInterest()
{
super.year=(int)Math.floor(this.year);
double r=this.year-(int)Math.floor(this.year);
int day=(int)(r*1000);//天数
double yearInterest=super.computerInterest();
double dayInterest=day*0.0001*savedMoney;
interest=yearInterest+dayInterest;
System.out.printf("%d元存在建设银行%d年零%d天的利息:%f元\n",savedMoney,super.year,day,interest);
return interest;
}
}
BankOfQingdao类:
import java.lang.Math;
public class BankOfQingdao extends Bank {
double year;
public double computerInterest()
{
super.year=(int)Math.floor(this.year);
double r=this.year-(int)Math.floor(this.year);
int day=(int)(r*1000);//天数
double yearInterest=super.computerInterest();
double dayInterest=day*0.00015*savedMoney;
interest=yearInterest+dayInterest;
System.out.printf("%d元存在青岛银行%d年零%d天的利息:%f元\n",savedMoney,super.year,day,interest);
return interest;
}
}
CommercialBank类:
public class CommercialBank extends Bank {
double year;
public double computerInterest()
{
super.year=(int)Math.floor(this.year);
double r=this.year-(int)Math.floor(this.year);
int day=(int)(r*1000);//天数
double yearInterest=super.computerInterest();
double dayInterest=day*0.00012*savedMoney;
interest=yearInterest+dayInterest;
System.out.printf("%d元存在商业银行%d年零%d天的利息:%f元\n",savedMoney,super.year,day,interest);
return interest;
}
}
Text测试主类:
public class Text {
public static void main(String args[]){
//50000元在建设银行存5年零216天的利息。
ConstructionBank bank1=new ConstructionBank();
bank1.year=5.216;
bank1.savedMoney=50000;
bank1.computerInterest();
//50000元在青岛银行存5年零216天的利息。
BankOfQingdao bank2=new BankOfQingdao();
bank2.year=5.216;
bank2.savedMoney=50000;
bank2.computerInterest();
//利息差额
System.out.printf("利息差额:"+(bank1.interest-bank2.interest)+"\n\n");
//8000元存在商业银行8年零236天的利息.
CommercialBank bank3=new CommercialBank();
bank3.year=8.236;
bank3.savedMoney=80000;
bank3.computerInterest();
}
}
运行结果:
三、用类封装手机的基本属性和功能
用类封装手机的基本属性和功能,要求手机即可以使用移动公司的SIM卡也可以使用联通公司SIM卡(可以使用任何公司提供的SIM卡)。
①.设计抽象类:设计一个抽象类SIM,该类有三个抽象方法:giveNumber()、setNumber()和giveCorpName()
②.设计手机类:设计MobileTelephone,该类有useSIM(SIM card)方法
③.各公司手机卡类:设计SIMOfChinaMobile、SIMOfChinaUnicom类
各类之间的关系如下:
编程定义各类,并在主类中进行测试。
SIM类:
public abstract class SIM {
//抽象类,抽象方法
abstract void setNumber(String s);
abstract String giveNumber();
abstract String giveCorpName();
}
MobileTelephone类:
public class MobileTelephone{
SIM card;
void useSIM(SIM card){
this.card=card;
}
void showMess(){
}
}
SIMOfChinaMobile类:
public class SIMOfChinaMobile extends SIM {
String number;
@Override
String giveNumber(){
return number;
}
@Override
void setNumber(String number){
this.number=number;
}
@Override
String giveCorpName(){
return "中国移动";
}
}
SIMOfChinaUnicom类:
public class SIMOfChinaUnicom extends SIM {
String number;
@Override //该符号代表重写,帮助读代码的时候理解,可以当一个注释用。
String giveNumber(){
return this.number;
}
@Override
void setNumber(String number){
this.number=number;
}
@Override
String giveCorpName(){
return "中国联通";
}
}
Text 测试主类:
public class Text {
public static void main(String[] args) {
//一部手机既可以使用移动公司的SIM卡,也可以使用联通公司SIM卡。
MobileTelephone phone =new MobileTelephone();
SIMOfChinaUnicom sim1=new SIMOfChinaUnicom();
sim1.setNumber("123456789");
System.out.printf("SIM1卡手机号:"+sim1.giveNumber()+"\n");
System.out.printf("SIM1卡通信公司:"+sim1.giveCorpName()+"\n");
phone.useSIM(sim1);
SIMOfChinaMobile sim2=new SIMOfChinaMobile();
sim2.setNumber("987654321");
System.out.printf("SIM2卡手机号:"+sim2.giveNumber()+"\n");
System.out.printf("SIM2卡通信公司:"+sim2.giveCorpName()+"\n");
phone.useSIM(sim2);
}
}
运行结果:
四、公司支出的总薪水
要求有一个abstract类,类名为Employee。Employee的子类有YearWorker、MonthWorker、WeekWorker。YearWorker对象按年领取薪水,MonthWorker按月领取薪水,WeekWorker按周领取薪水。Employee类有一个abstract方法:
public abstract earnings();
子类必须重写父类的earnings()方法,给出各自领取报酬的具体方式。
有一个Company类,该类用Employee对象数组作为成员,Employee对象数组的元素可以是YearWorker对象的上转型对象、MonthWorker对象的上转型对象或WeekWorker对象的上转型对象。程序能输出Company对象一年需要支付的薪水总额。
本题考察:上转型对象。
Employee类:
public abstract class Employee {
public abstract double earnings();
}
WeekWorker类:
public class WeekWorker extends Employee {
int week;
double weekSalary;
WeekWorker(int w,double s){
week=w;
weekSalary=s;
}
public double earnings(){
return this.week*this.weekSalary;
}
}
MonthWorker类:
public class MonthWorker extends Employee {
int month;
double monthSalary;
MonthWorker(int m,double s){
month=m;
monthSalary=s;
}
public double earnings(){
return this.month*this.monthSalary;
}
}
YearWorker类:
public class YearWorker extends Employee {
int year;
double yearSalary;
YearWorker(int y,double s){
year=y;
yearSalary=s;
}
public double earnings(){
return this.year*this.yearSalary;
}
}
Company类:
public class Company {
//Employee对象数组作为成员
Employee[] employee;
//构造函数
Company(Employee[] employee) {
this.employee=employee;
}
}
CompanySalary类:
public class CompanySalary {
public static void main(String[] args) {
//定义一个employee类对象数组
Employee[] employee=new Employee[3];
//employee[0]是YearWorker的上转型对象
employee[0]=new YearWorker(1,48000.0);
//employee[1]是MonthWorker的上转型对象
employee[1]=new MonthWorker(12,4000.0);
//employee[2]是WeekWorker的上转型对象
employee[2]=new WeekWorker(48,1000.0);
Company com=new Company(employee);
double sumSalary;
sumSalary=employee[0].earnings()+employee[1].earnings()+employee[2].earnings();
System.out.println("公司支出的总薪水为:"+sumSalary);
}
}
五、通过类来求三种图形的面积
对于各种几何图形,一般都有求图形的面积、周长等方法。现在有圆、矩形和三角形三种图形,要求通过类来实现求三种图形的面积。
三种图形都有相同的方法,因此可以抽象出一个抽象类:图形类,该类有抽象的求面积方法。然后由该抽象类生成3个子类:圆类、矩形类、三角形类。在主类中实现求各类图形的面积。
各类之间的关系如下:
在子类中,定义构造方法,实现对子类成员变量的初始化。
编程定义各类,并在主类中进行测试。
Figure类:
public abstract class Figure {
abstract double area();
}
Circle类:
public class Circle extends Figure {
double r;
Circle(double r){
this.r=r;
}
double area(){
return Math.pow(this.r, 2)*Math.PI;
}
}
Rectangle类:
public class Rectangle extends Figure {
double lengh;
double weigh;
Rectangle(double lengh,double weigh){
this.lengh=lengh;
this.weigh=weigh;
}
double area(){
return this.lengh*this.weigh;
}
}
Triangle类:
public class Triangle extends Figure {
double high;
double bottom;
Triangle(double high,double bottom){
this.high=high;
this.bottom=bottom;
}
double area(){
return 0.5*this.high*this.bottom;
}
}
Text类:
public class Text {
public static void main(String[] args) {
Circle circle1=new Circle(5);
Rectangle rectangle1=new Rectangle(10,5);
Triangle triangle1=new Triangle(10,5);
System.out.println("圆的面积:"+circle1.area());
System.out.println("矩形面积:"+rectangle1.area());
System.out.println("三角形面积:"+triangle1.area());
}
}
六、动物声音模拟器
设计一个动物声音“模拟器”,希望模拟器可以模拟许多动物的叫声,要求如下:
(1)编写抽象类Animal
Animal抽象类有2个抽象方法cry()和getAnimalName(),即要求各种具体的动物给出自己的叫声和种类名称。
(2)编写模拟器类Simulator
该类有一个playSound(Animal animal)方法,该方法的参数是Animal类型。即参数animal可以调用Animal的子类重写的cry()方法播放具体动物的声音,调用子类重写的getAnimalName()方法显示动物种类的名称。
(3)编写Animal类的子类:Dog和Cat类
在各子类中通过构造方法实现对子类成员变量的初始化。
(4)编写主类Application(用户程序)
在主类Application的main方法中至少包含如下代码。
Simulator simulator = new Simulator();
simulator.playSound(new Dog(“藏獒”));
simulator.playSound(new Cat(“加菲猫”));
各类的UML图如下所示:
Animal类:
public abstract class Animal {
abstract void cry();
abstract String getAnimalName();
}
Cat类:
public class Cat extends Animal {
String name;
Cat(String name){
this.name=name;
}
void cry() {
System.out.println("喵喵喵~");
}
String getAnimalName() {
return name;
}
}
Dog类:
public class Dog extends Animal {
String name;
Dog(String name){
this.name=name;
}
void cry() {
System.out.println("汪汪汪~");
}
String getAnimalName() {
return name;
}
}
Simulator类:
public class Simulator {
void playSound(Animal animal){
System.out.println( animal.getAnimalName() + " may cry like this: ");
animal.cry();
}
}
Text类:
public class Text {
public static void main(String[] args) {
Simulator simulator = new Simulator();
simulator.playSound(new Dog("藏獒"));
simulator.playSound(new Cat("加菲猫"));
}
}
运行结果: