第八章多态和接口内容回顾•继承的概念及特点•方法重写的特点•抽象类及抽象方法本讲内容•继承实现的多态•类型转换与instanceof运算符•接口•接口实现的多态•面向接口的编程本讲目标•掌握多态的概念及用法。•掌握接口的概念及用法多态•宠物生病了,需要主人给宠物看病–不同宠物看病过程不一样–不同宠物恢复后体力值不一样打针吃药吃药疗养狗狗Q仔•编写主人类–编写给狗狗看病的方法–编写给Q仔看病的方法为什么使用多态publicclassMaster{publicvoidCure(Dogdog){if(dog.getHealth()50){dog.setHealth(60);System.out.println(打针、吃药);}}publicvoidCure(Penguinpenguin){if(penguin.getHealth()50)penguin.setHealth(70);System.out.println(吃药、疗养);}}主人类……Mastermaster=newMaster();master.Cure(dog);master.Cure(penguin);……测试方法为什么使用多态•如果又需要给XXX看病,怎么办?–添加XXX类,继承Pet类–修改Master类,添加给XXX看病的方法使用多态优化设计频繁修改代码,代码可扩展性、可维护性差为什么使用多态•使用多态优化后的代码……Petpet=newDog();Mastermaster=newMaster();master.Cure(pet);……测试方法publicclassDogextendsPet{publicvoidtoHospital(){this.setHealth(60);System.out.println(打针、吃药);}}publicclassPenguinextendsPet{publicvoidtoHospital(){this.setHealth(70);System.out.println(吃药、疗养);}}publicclassMaster{publicvoidCure(Petpet){if(pet.getHealth()50)pet.toHospital();}}主人类Dog类Penguin类1234又要给XXX看病时,只需:1.编写XXX类继承Pet类(旧方案也需要)2.创建XXX类对象(旧方案也需要)3.其他代码不变(不用修改Master类)什么是多态•生活中的多态–你能列举出一个多态的生活示例吗?•程序中的多态多态:同一个引用类型,使用不同的实例而执行不同操作父类引用,子类对象同一种事物,由于条件不同,产生的结果也不同实现多态要素•实现多态的两个要素:–1.方法重写–2.使用父类类型方法重写•方法重写的规则–在继承关系的子类中–重写的方法名、参数、返回值类型必须与父类相同–私有方法不能继承因而也无法重写位置方法名参数表返回值访问修饰符方法重写子类相同相同相同不能比父类更严格方法重载同类相同不同无关无关方法重写方法重载VS类型转换•子类转换为父类:自动转换•假设A类是B类的父类,当我们用子类创建一个对象,而这个对象的引用放到父类的对象中时。–Aa;a=newB();–或Aa;Bb=newB();a=b;–称这个父类对象a是子类对象的上转型对象。–例如:“老虎是哺乳动物”,哺乳类是老虎类的父类,但这样说将失掉老虎独有的属性。类型转换•子类转换为父类细节–上转型对象不能操作子类新增的成员变量和方法。–上转型对象可以操作子类继承或重写的成员变量和方法–如果子类重写了父类的某个方法,上转型对象调用该方法时,是调用的重写方法。•父类转换为子类:强制转换instanceof运算符•该运算符用来判断一个对象是否属于一个类或者实现了一个接口,结果为true或false•在强制类型转换之前通过instanceof运算符检查对象的真实类型,可以避免类型转换异常,从而提高代码健壮性对象instanceof类或接口/***测试instanceof运算符的使用。*@author北大青鸟*/publicclassTestPoly2{publicstaticvoidmain(String[]args){Petpet=newPenguin(楠楠,Q妹);//Petpet=newDog(欧欧,雪娜瑞);pet.eat();if(petinstanceofDog){Dogdog=(Dog)pet;dog.catchingFlyDisc();}elseif(petinstanceofPenguin){Penguinpgn=(Penguin)pet;pgn.swimming();}}}/***测试instanceof运算符的使用。*@author*/publicclassTestPoly2{publicstaticvoidmain(String[]args){//Petpet=newPenguin(楠楠,Q妹);Petpet=newDog(欧欧,雪娜瑞);pet.eat();if(petinstanceofDog){Dogdog=(Dog)pet;dog.catchingFlyDisc();}elseif(petinstanceofPenguin){Penguinpgn=(Penguin)pet;pgn.swimming();}}}注释创建Penguin对象语句,取消创建Dog对象语句的注释为什么使用接口•只有抽象方法的抽象类?可以用接口来表示接口有比抽象类更好的特性:1.可以被多继承2.设计和实现完全分离3.更自然的使用多态4.更容易搭建程序框架5.更容易更换实现……用接口代替这样的抽象类,是因为:接口•认识一下接口•必须知道的接口特性–接口不可以被实例化–实现类必须实现接口的所有方法–实现类可以实现多个接口–接口中的变量都是静态常量publicinterfaceMyInterface{publicvoidfoo();//其他方法}所有方法都是:publicabstract抽象类除外Java中的多继承常作为类型使用如何使用接口•用程序描述USB接口如何使用接口•可以使用Java接口来实现USB接口本身没有实现任何功能USB接口规定了数据传输的要求USB接口可以被多种USB设备实现编写USB接口实现USB接口使用USB接口根据需求设计方法实现所有方法用多态的方式使用如何使用接口•编码实现publicclassUDiskimplementsUsbInterface{publicvoidservice(){System.out.println(连接USB口,开始传输数据。);}}publicinterfaceUsbInterface{/***USB接口提供服务。*/voidservice();}UsbInterfaceuDisk=newUDisk();uDisk.service();编写接口实现接口使用接口实现接口使用的关键字用接口实现多态多个接口使用“,”分隔接口的定义•接口的定义:是特殊的抽象类,只包含常量和方法的声明,而没有变量定义和方法的实现•接口的含义:–接口是一种约定–面向接口编程体现在接口名称和注释上程序设计时面向接口的约定而不考虑具体实现有些接口只有名称方法的实现方式要通过注释来约定找出错误•阅读代码,找出错误publicinterfaceMyInterface{publicMyInterface();publicvoidmethod1();publicvoidmethod2(){}privatevoidmethod3();voidmethod4();intmethod5();intTYPE=1;}接口表示一种能力•“做这项工作需要一个钳工(木匠/程序员)”•接口是一种能力•面向接口编程关心实现类有何能力,而不关心实现细节钳工是一种“能力”,不关心具体是谁体现在接口的方法上面向接口的约定而不考虑接口的具体实现程序设计时面向接口编程•软件工程师不但要会写代码,还要懂业务•软件工程师需要两种能力会写代码会讲业务不是软件工程师特有一个人可以具有多项能力,一个类可以实现多个接口面向接口编程•实现过程定义Programmer接口定义BizAgent接口具备编码的能力具备讲解业务的能力编写SoftEngineer类实现两个接口编写测试类让软件工程师写代码、讲业务接口相关规则•接口相关规则–接口中所有方法都是抽象的。–即使没有显式的将接口中的成员用public标识,也是public访问类型的–接口中变量默认用publicstaticfinal标示,所以接口中定义的变量就是全局静态常量。–可以定义一个新接口,用extends去继承一个已有的接口–可以定义一个类,用implements去实现一个接口中所有方法。–可以定义一个抽象类,用implements去实现一个接口中部分方法。接口•C++支持多重继承,Java支持单重继承•C++多重继承的危险性在于一个类可能继承了同一个方法的不同实现,会导致系统崩溃。•Java中,一个类只能继承一个类,但同时可以实现多个接口,既可以实现多重继承的效果和功能,也避免的多重继承的危险性。•classStudentextentsPersonimplementsRunner,Flyer{…}注意:extends必须位于implements之前总结你学到了吗?•如何使用多态?•引用数据类型的转换•如何使用接口?•如何进行面向接口的编程?上机练习•1、结合课堂案例,实现喂养宠物功能:–实现喂养宠物功能•不同宠物吃的东西不同•主人可以喂养不同类型宠物–练习功能知识点:•子类到父类的自动类型转换•使用父类作为方法形参实现多态•多态可以减少代码量,可以提高代码的可扩展性和可维护性上机练习•2.创建一个EatBehavior接口,该接口提供一个eat()抽象方法:–为该接口提拱两个实现类,中餐和西餐(ChineseMeal和WesternStyleFood)–创建一个Person抽象类,该类中有描述人的姓名和年龄和吃饭(EatBehavior)三个属性,分别可通过get/set方法来访问,并有一个performEat()方法(该方法通过调用EatBehavior接口的eat方法来完成功能)和三个属性的构造器;中国人(Chinese)和美国人(American)两个类分别继承Person类,中国人吃中餐,美国人吃西餐–创建一个Test类进行测试。