11-多态
一、多态
对于不同对象接收到同一指令之后可以进行不同的处理就是多态
对应程序中就是不同对象调用同一个方法名后, 每个对象具体的子类实现是不一样的
为什么使用多态?
▪ 宠物饿了,需要主人给宠物喂食
– 不同宠物吃的东西不一样
– 不同宠物恢复后体力值不一样
/* ▪ 狗狗类 – 增加狗狗吃东西的方法 ▪ 企鹅类 – 增加企鹅吃东西的方法 ▪ 创建主人类 – 编写给狗狗喂东西的方法 – 编写给企鹅喂东西的方法 ▪ 编写测试方法 – 调用主人类给狗狗喂的方法 – 调用主人类给企鹅喂的方法 */
先写一个简单的例子:
public abstract class Pet { public abstract void feed(); }
public class Dog extends Pet { @Override public void feed() { System.out.println("狗在吃骨头"); } }
public class Cat extends Pet { @Override public void feed() { System.out.println("猫在吃鱼"); } }
public class Person{ // public void feed(Cat cat){ // cat.feed(); // } // // public void feed(Dog dog){ // dog.feed(); // } public void feed(Pet pet){ pet.feed(); } public static void main(String[] args) { Person p = new Person(); Pet dog = new Dog(); Pet cat = new Cat(); p.feed(dog); p.feed(cat); } }
打印结果为:
/* 狗在吃骨头 猫在吃鱼 */
调用了同一个方法但是给出的反应是不一样的, 这就是一个简单的多态
/* * 多态: * 对应同一个指令(调用同一个名称的方法),不同的对象给予不同的反应(不同的方法实现) * 规范(多态实现的提前): * 1、必须要有继承关系 // Dog Cat 继承了 Pet * 2、子类方法必须重写父类的方法 * 3、父类引用指向子类对象 // Pet dog = new Dog(); 自动类型转换 比如基本数据类型小的向大的转换自动转换,大的转为小的会造成精度损失 * 多态的目的: * 为了提高代码的扩展性和维护性 * 方便代码逻辑的编写 * 多态的两种表现形式: * 1、父类作为方法的参数 * 2、父类作为方法的返回值类型 * * 引用类型的转换跟基本数据类型的转换类似: * 1、当父类需要转成子类的时候,要进行强制转换,但是在强制转换之前一定要先判断父类引用指向的子类对象到底是谁, * 如果无法确定,在运行过程中可以出错 * 2、当子类需要向父类转换的时候,直接自动转换,不需要进行任何的判断。 * * */
▪ 如果再领养XXX宠物,就需要给XXX喂食,怎么办?
– 添加XXX类,继承Pet类,实现吃食方法
– 修改Master类,添加给XXX喂食的方法
public class Penguin extends Pet { @Override public void feed() { System.out.println("企鹅在吃。。。。"); } }
public class Person{ // public void feed(Cat cat){ // cat.feed(); // } // // public void feed(Dog dog){ // dog.feed(); // } public void feed(Pet pet){ pet.feed(); } public void play(Pet pet){ pet.play(); } public static void main(String[] args) { Person p = new Person(); Pet dog = new Dog(); Pet cat = new Cat(); Pet penguin = new Penguin(); p.feed(dog); p.feed(cat); p.feed(penguin); p.play(dog); p.play(cat); } }
public class Person{ // public void feed(Cat cat){ // cat.feed(); // } // // public void feed(Dog dog){ // dog.feed(); // } public void feed(Pet pet){ pet.feed(); } public void play(Pet pet){ pet.play(); } public Pet buyPet(int type){ if(type==1){ return new Dog(); }else if(type == 2){ return new Cat(); }else{ return new Penguin(); } } public static void main(String[] args) { Person p = new Person(); // Person p1 = (Person)dog; Pet pet = p.buyPet(2); if(pet instanceof Dog){ System.out.println("买的是一只狗"); }else if(pet instanceof Cat){ System.out.println("买的是一只猫"); }else{ System.out.println("买的是一只企鹅"); } } }
练习2:
计算一次租赁多辆汽车的总租金2-1
▪ 训练要点:
– 多态的使用
– 使用父类类型作为方法参数
▪ 需求说明:
– 在前面汽车租赁系统的基础上,实现计算多种车辆总租金的功能
– 现在有客户租用
▪ 2辆宝马
▪ 1辆别克商务舱
▪ 1辆金龙(34)座
▪ 租5天共多少租金?
public abstract class MotoVehicle { private int no; private String brand; public MotoVehicle(){ } public MotoVehicle(int no,String brand){ this.no = no; this.brand = brand; } public int getNo() { return no; } public void setNo(int no) { this.no = no; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public abstract int calcRent(int day); }
public class Car extends MotoVehicle{ private String type; public Car(){ } public Car(String type) { this.type = type; } public Car(int no,String brand,String type){ super(no,brand); this.type= type; } public String getType() { return type; } public void setType(String type) { this.type = type; } @Override public int calcRent(int day) { if(type.equals("0")){ return 600*day; }else if(type.equals("1")){ return 500*day; }else if(type.equals("2")){ return 300*day; }else{ System.out.println("类型不匹配"); return 0; } } }
public class Bus extends MotoVehicle { private int seatcount; public Bus(){ } public Bus(int no,String brand,int seatcount){ super(no,brand); this.seatcount = seatcount; } public int getSeatcount() { return seatcount; } public void setSeatcount(int seatcount) { this.seatcount = seatcount; } @Override public int calcRent(int day) { if(seatcount>16){ return 1500*day; }else{ return 800*day; } } }
public class TestMotoVehicle { public static void main(String[] args) { // MotoVehicle moto = new MotoVehicle(); // Car car = new Car(1,"宝马","1"); // System.out.println("租金是:"+car.calcRent(5)); // Bus bus = new Bus(2,"金龙",20); // System.out.println("租金是:"+bus.calcRent(5)); MotoVehicle[] moto = new MotoVehicle[4]; moto[0] = new Car(1,"宝马","1"); moto[1] = new Car(1,"宝马","1"); moto[2] = new Car(2,"别克","2"); moto[3] = new Bus(3,"金龙",34);
int totalMoney = calcTotal(moto); System.out.println("总租金是:"+totalMoney); } public static int calcTotal(MotoVehicle[] moto){ int totalMoney = 0; for(int i = 0;i<moto.length;i++){ totalMoney+=moto[i].calcRent(5); } return totalMoney; } }
练习3:
购置新车2-1
▪ 训练要点:
– 使用父类作为方法形参实现多态
– 使用多态增强系统的扩展性和可维护性
▪ 需求说明:
– 新购置了卡车,根据吨位,租金每吨每天50
– 对系统进行扩展,计算汽车租赁的总租金
public class Track extends MotoVehicle { private int weight; public Track(){ } public Track(int no,String brand,int weight){ super(no,brand); this.weight = weight; } @Override public int calcRent(int day) { return 50*day*weight; } }
public class TestMotoVehicle { public static void main(String[] args) { // MotoVehicle moto = new MotoVehicle(); // Car car = new Car(1,"宝马","1"); // System.out.println("租金是:"+car.calcRent(5)); // Bus bus = new Bus(2,"金龙",20); // System.out.println("租金是:"+bus.calcRent(5)); MotoVehicle[] moto = new MotoVehicle[5]; moto[0] = new Car(1,"宝马","1"); moto[1] = new Car(1,"宝马","1"); moto[2] = new Car(2,"别克","2"); moto[3] = new Bus(3,"金龙",34); moto[4] = new Track(4,"解放",50); int totalMoney = calcTotal(moto); System.out.println("总租金是:"+totalMoney); } public static int calcTotal(MotoVehicle[] moto){ int totalMoney = 0; for(int i = 0;i<moto.length;i++){ totalMoney+=moto[i].calcRent(5); } return totalMoney; } }
二、小结
/* 类型转换 向上转型——子类转换为父类,自动进行类型转换 向下转型——父类转换为子类,结合instanceof运算符进行强制类型转换 实现多态的两种方式 使用父类作为方法形参实现多态 使用父类作为方法返回值实现多态 使用多态的好处? 多态可以减少类中代码量,可以提高代码的可扩展性和可维护性 引用变量的两种类型: 编译时类型(模糊一点,一般是一个父类) 由声明时的类型决定。 运行时类型(运行时,具体是哪个子类就是哪个子类) 由实际对应的对象类型决定。 多态的存在要有3个必要条件: 要有继承,要有方法重写,父类引用指向子类对象 */