1、多态性 继承层次结构中子类对象和父类对象间的关系 抽象类和抽象方法的声明和使用 接口的声明和实现 实现多态性的编程技术final修饰符内部类与事件处理基本数据类型的包装类先来看一个例子,预测下程序运行的结果。多态性(Polymorphism)在父类中定义的行为,被子类继承之后,表现出不同的行为。效果:同一行为在父类及其各个子类中具有不同的语义。引用变量既可以指向相同类型的类的对象,也可以指向该类的任何一个子类的对象。向上转型:将子类对象直接赋值给父类引用的过程,不需要强制类型转换,由系统自动完成(已存在“is a”关系)public class Test public static void
2、main(String args)/子类对象送给父类引用Animal a=new Bird();Java语言中Object是所有类的直接或间接父类,也就是说,任何类型的对象都可以赋值给Object引用。【说明【说明 】如果把子类对象赋给父类引用】如果把子类对象赋给父类引用(将子类对象当作父类对象看待),那么(将子类对象当作父类对象看待),那么就只能调用父类中已有的方法。就只能调用父类中已有的方法。人类 说话()走路()解答Java中的问题()Animal a=new Bird();Animal a=new Bird();引用变量引用变量a a可以调用的方法有哪些?可以调用的方法有哪些?动物类A
3、nimalmove()eat()鸟类Birdmove()sing()【说明【说明 】如果子类把父类方法覆盖了,】如果子类把父类方法覆盖了,再把子类对象赋给父类引用,通过父类再把子类对象赋给父类引用,通过父类引用调用该方法时,调用的是子类重写引用调用该方法时,调用的是子类重写之后的方法。之后的方法。动物类Animalmove()eat()鸟类Birdmove()sing()public class Test public static void main(String args)/子类对象送给父类引用Animal a=new Bird();a.move();Animal a=new Bird()
4、;Animal a=new Bird();a.movea.move()()执行的是谁的执行的是谁的move()move()方法?方法?举例Bird b=new Bird(bird1,4);b.move();b.sing();b.eat();Animal a1=new Animal(animal1,20);a1.move();a1.eat();Animal a2=new Bird(bird2,4);a2.sing();a2.eat();a2.move();动物类Animalmove()eat()鸟类Birdmove()sing()/出错,父类中没有该方法/执行子类move方法/执行父类eat方法
5、 子类对象赋给父类引用后的3个层次(1)父类中没有的方法(如sing()方法)不能调用。(2)如果子类没有覆盖父类的方法(如eat()方法),则调用父类的方法。(3)如果子类覆盖父类的方法(如move()方法),则调用子类的方法。动态绑定技术:Java虚拟机实现,多态的基础静态绑定技术:编译器动态绑定的作用:无需对现存的代码进行修改,就可以对程序进行扩展。举例动物类Animalmove()eat()鸟类Birdmove()sing()鱼类 Fishmove()Java编译器允许在具有直接或间接继承关系的类之间进行类型转换。子类对象-父类引用(向上转型)父类引用-子类引用(向下转型)动物类Ani
6、malmove()eat()鸟类Birdmove()sing()向向上上转转型型向向下下转转型型向下转型 必须使用强制类型转换 必须在有意义的情况下进行,即强转必须是合理的 编译器对于强制类型转换采取的是一律放行的原则(只检查语义)Animal animal=new Animal();Bird bird=(Bird)animal;Bird bird=(Bird)xxx;无论xxx是哪种类型,编译器都不会报错。编译无错,运行出错,ClassCastException异常Animal a=new Fish();Animal b=new Bird();Animal c=new Animal();if
7、(a instanceof Animal)?if(b instanceof Animal)?if(c instanceof Animal)?if(a instanceof Bird)?if(b instanceof Fish)?if(c instanceof Fish)?动物类Animalmove()eat()鸟类Birdmove()sing()鱼类 Fishmove()【例6-1】在Employee类中重写java.lang.Object中的equals()方法。设有员工Employee类,包含工号id、姓名name、工资salary等属性。当工号id与姓名name均相同时,两个对象相等。p
8、ublic boolean equals(Object obj)return this=obj;Object类中的equals()方法功能:比较参数所指定的对象是否与当前对象“相等”。对于任何非空引用变量x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法返回 true。public class EqualsTest public class EqualsTest public static void main(String args)public static void main(String args)Employee e1=new Employee();Employee e1=ne
9、w Employee();e1.setId(001);e1.setId(001);e1.setName(zhang);e1.setName(zhang);Employee e2=e1;Employee e2=e1;System.out.println(“e1:+e1);System.out.println(“e1:+e1);System.out.println(“e2:+e2);System.out.println(“e2:+e2);System.out.println(“e1=e2?+e1.equals(e2);System.out.println(“e1=e2?+e1.equals(e2)
10、;public boolean equals(Object obj)return(this=obj);Employee e3=new Employee(“001”,zhang);System.out.println(“e1=e3?+e1.equals(e3);如何利用如何利用equals()方法比较对象的内容?方法比较对象的内容?System.out.println(“e3:+e3);Employee类对象相等的条件是Id和name都相同。public boolean equals(Object obj)if(obj instanceof Employee)Employee e=(Employ
11、ee)obj;return this.name.equals(e.name)&this.id.equals(e.id);return false;向下转型向下转型public boolean equals(Object obj)return(this=obj);public class EqualsTest public static void main(String args)Employee e1=new Employee(”001”,“zhang”);Employee e2=new Employee(”001”,“zhang”);System.out.println(e1=e2?+e1.
12、equals(e2);动态绑定动态绑定6.2.1 抽象类及抽象方法的定义6.2.2 为什么设计抽象类6.2.3 开闭原则抽象类抽象类:至少包含一个抽象方法的类。抽象方法抽象方法:没有实现的方法,由abstract修饰。它的实现交给子类根据自己的情况去实现。public public abstract abstract class Animal class Animal private private String name;String name;public abstract void move();/public abstract void move();/抽象方法抽象方法 public
13、Animal()/public Animal()/构造方法,抽象类中可以有构造方法构造方法,抽象类中可以有构造方法 public String public String getNamegetName()/()/非抽象方法,抽象类中可以有非抽象方法非抽象方法,抽象类中可以有非抽象方法return this.name;return this.name;【练习练习】完成如下代码的设计。完成如下代码的设计。抽象类 Shapename抽象方法 getArea()Shape()Shape(String)getName()圆 CirclergetArea()Circle(String,double)矩形
14、Rectanglelength,widthgetArea()Rectangle(String,double,double)圆 CirclergetArea()Circle(String,double)矩形 Rectanglelength,widthgetArea()Rectangle(String,double,double)publicpublic classclass Test publicpublic staticstatic voidvoid main(String args)Shape shape;shape=newnew Circle(circle,5);System.out.pr
15、intln(shape.getName()+:+shape.getArea();shape=newnew Rectangle(rect,10,8);System.out.println(shape.getName()+:+shape.getArea();向上转型向上转型向上转型向上转型多态多态多态多态我们可以构造出一组行为的抽象描述,但是这组行为却能够有任意个可能的具体实现方式。这个抽象描述就是抽象类,而这一组任意个可能的具体实现则由所有可能的派生类表现。开闭原则OCP(Open-Closed Principle)面向对象设计的一个最核心的原则 对于扩展是开放的,对于修改是关闭的一个程序员累昏
16、倒了,在医院昏迷了好几天,家人哭的稀里哗啦的,老婆孩子在旁边怎么叫就是不醒。一天他同事来看他,第一句话就是对着躺在病床上的他说:需求又变了。奇迹发生了,那个程序员一下从病床上做起来了。【例6-2】为某个系统设计方案,要求能显示各种类型的图表,如饼图和柱状图等。ChartDisplay+display(type:String):voidPieChart+display():voidBarChart+display():void新的需求:增加显示一种新的图表-折线图。方案一在设计好折线图类LineChart后,需要修改ChartDisplay类的display()方法的源代码,增加新的判断逻辑:i
17、f(type.equalsIgnoreCase(pie)PieChart chart=new PieChart();chart.display();else if(type.equalsIgnoreCase(bar)BarChart chart=new BarChart();chart.display();else if(type.equalsIgnoreCase(line)LineChart chart=new LineChart();chart.display();违反了开闭原则,没有实现对修改是关闭的ChartDisplay-chart:AbstractChart+ChartDispla
18、y()+ChartDisplay(chart:AbstractChart)+setChart(chart:AbstractChart):void+show():voidAbstractChart+display():voidPieChart+display():voidBarChart+display():voidpublic void show()chart.display();方案二6.3.1 接口的定义和实现6.3.2 接口与抽象类的区别接口接口 接口由常量和一组抽象方法组成。接口支持多重继承。一个类可以同时实现多个接口。一个接口可以同时继承自多个接口(不会产生二义性)。指出下面代码中错
19、误的部分。public interface Introduce public String detail();public void introduction()detail();private void showMessage();void speak();Java接口中不能有方法实现接口中不能有方法实现Java接口中的方法必须是接口中的方法必须是public定义接口的一般格式 public interface 接口名接口名 extends 父接口名列表父接口名列表 public final static 类型类型 常量名常量名=常量值;常量值;public abstract 返回类型返回类
20、型 方法名方法名(参数列表参数列表);public interface ChineseEmployee String nationality=Chinese;/public static final double pay();/abstract父子关键字关系类类extends单一接口类implements多重接口接口extends多重类接口不存在如果一个类实现一个接口,且实现接口中声明的所有方法时,那么这个类才是具体的类;否则它还是一个抽象的类。抽象类和接口是支持开闭原则中抽象层定义的两种机制区别1(次要):从语法层面上抽象类和接口的区别很明显,抽象类可以有非常量的数据成员,也可以有非抽象的方
21、法,甚至它可以有构造方法(虽然抽象类不能创建实例,但是构造方法为其子类对象的创建做好准备);而接口只能有静态、常量的数据成员,只能有抽象方法,不能有构造方法。抽象类支持单继承;接口支持多继承。区别2(次要):从编程的角度看,抽象类中的非抽象方法可以定义对象的默认行为方式,而接口中的方法永远只有一个驱壳,没有行为方式。区别3(主要):面向对象的设计实际是看世界的一个过程,所以设计理念上的区别才是抽象类和接口的本质不同。我们应该在对问题领域的本质的理解,以及对设计意图的理解的基础上正确地选择它们。【例6-4】门和报警门的设计。假设在问题领域中有一个关于门Door的抽象概念,该Door具有两个动作o
22、pen和close。使用抽象类作为中间层或者使用接口作为中间层publicpublic abstractabstract classclass Door publicpublic abstractabstract voidvoid open();publicpublic abstractabstract voidvoid close();publicpublic interfaceinterface Door publicpublic voidvoid open();publicpublic voidvoid close();需求变化:要求Door还要具有报警的功能,该如何设计类结构呢?pub
23、licpublic abstractabstract classclass Door publicpublic abstractabstract voidvoid open();publicpublic abstractabstract voidvoid close();publicpublic abstractabstract voidvoid alarm();在在DoorDoor的定义中把的定义中把DoorDoor概念概念本身固有的行为方法本身固有的行为方法(open()open()和和close()close())和另外)和另外一个概念一个概念“报警器报警器”的行为的行为方法(方法(al
24、arm()alarm())混在了一起,)混在了一起,使那些使那些仅仅依赖于仅仅依赖于DoorDoor这个这个概念的模块会因为概念的模块会因为“报警器报警器”的改变(例如修改的改变(例如修改alarm()alarm()方方法的参数)而改变法的参数)而改变。publicpublic interfaceinterface Door publicpublic voidvoid open();publicpublic voidvoid close();public void alarm();public void alarm();6.4.1 案例分析6.4.2面向接口编程的代码组织面向接口编程的代码组织
25、【例6-5】现要开发一个应用,模拟移动存储设备的读写,即模拟计算机与U盘、移动硬盘、MP3等设备间的数据交换。现已确定有U盘、移动硬盘、MP3播放器三种设备,但以后可能会有新的移动存储设备出现,所以数据交换必须有扩展性,保证计算机能与目前未知、而以后可能会出现的存储设备进行数据交换。方案一方案一:分别定义U盘FlashDisk类、移动硬盘MobileHardDisk类、MP3播放器MP3Player类,实现各自的read()和write()方法。然后在Computer类中实例化上述三个类,为每个类分别定义读、写方法。未知未知设备设备FlashDiskMobileHardDiskMP3Playe
26、rComputer接口IMobileStorageread()/write()read()/write()read()/write()/playMusic()readData()wrieteData()IMobileStorage+read():void+write():voidComputer-usbDriver:IMobileStorage+Computer(usbDriver:IMobileStorage)+setUsbDriver(usbDriver:IMobileStorage):void+readData():void+writeData():voidFlashDriver+rea
27、d():void+write():voidMobileHardDisk+read():void+write():voidMP3Player+read():void+write():void应用层接口底层包结构1 1第一步,编写中间层接口IMobileStorage,定义方法,即系统的行为模型。第三步,编写应用层Computer类,依赖接口完成业务逻辑,屏蔽底层的实现。(1)将接口引用变量作为应用层的数据成员。(2)定义构造方法或set方法对接口数据成员初始化。(3)封装应用层的业务行为方法,通过接口成员调用接口中的方法实现业务逻辑。3 3第二步,编写底层各实现类,实现接口中的方法,直接操作底层
28、数据(接口的实现类通常放在接口的子包中,命名为“impl”)。2 2第四步,编写测试类Test,在main()方法中创建接口的实现类对象,传递给应用层实例,应用层实例调用应用层业务方法完成任务。4 4将学生(Student类)数据按照表格的方式输出。学生数据存储在不同的结构中,一种是二维字符串数组,每一行代表一个学生的数据;另一种是一维Student类型数组,每个元素代表一个学生。要求采用面向接口的方式设计架构,在接口层抽象出输出一个二维表格所需的所有方法,并在底层用两种存储方式分别予以实现。2应用层1接口3底层TableModel+getRowNumber():int+getColNumbe
29、r():int+getColName(index:int):String+getValue(row:int,col:int):ObjectPrintTable-model:TableModel+PrintTable(model:TableModel)+setModel(model:TableModel):void+printTable():voidTableModelForStringArray-data:String+TableModelForStringArray(data:String)+getRowNumber():int+getColNumber():int+getColName(i
30、ndex:int):String+getValue(row:int,col:int):ObjectTableModelForStudentArray-data:Student+TableModelForStudentArray(data:Student)+getRowNumber():int+getColNumber():int+getColName(index:int):String+getValue(row:int,col:int):ObjectStudent-id:String-name:String-gender:boolean-age:int+Student()+Student(id
31、:String,name:String,gender:boolean,age:int)+getId():String+getName():String+isGender():boolean+getAge)():int1接口层TableModelpublicpublic interfaceinterface TableModel publicpublic intint getRowNumber();/获取表格的行数publicpublic intint getColNumber();/获取表格的列数publicpublic String getColName(intint index);/获取表
32、头名称publicpublic Object getValue(intint row,intint col);/获取 row行col列的数据getValue()方法获取row行col列的表格数据,因为表格数据的类型并不统一,所以用最高类型Object作为返回值类型,允许该方法返回任何类型的数据。2底层实现类TableModelForStringArrayString str=ID,NAME,GENDER,AGE,1001,zhangs,男,21,1002,lis,男,23,1003,wangwu,女,21,1004,zhangs,男,24,1005,zhaol,女,25,1006,qingqi
33、,男,21;2应用层PrintTable类publicpublic classclass PrintTable privateprivate TableModel model;/接口成员publicpublic PrintTable()publicpublic PrintTable(TableModel model)/构造方法初始化接口成员变量thisthis.model=model;publicpublic voidvoid setModel(TableModel model)/set方法初始化接口成员变量thisthis.model=model;3底层实现类TableModelForStu
34、dentArrayStudent s=newnew Student(1001,zhangs,truetrue,21),newnew Student(1002,lisi,truetrue,24),newnew Student(1003,wangw,falsefalse,23),newnew Student(1004,zhaol,truetrue,25),newnew Student(1005,qianqi,falsefalse,20),newnew Student(1006,liuba,truetrue,22),;利用多态性面向接口(抽象类)编程 定义类继承自抽象类,并覆盖抽象方法;或者实现接口,实现接口中的方法。将子类对象赋值给抽象父类引用或接口引用。利用父类的这些引用调用子类中的同名方法。子类对象赋给父类引用后的3个层次 (1)父类中没有的方法子类对象不能调用。(2)如果子类没有覆盖父类的方法则调用父类的方法。(3)如果子类覆盖父类的方法则调用子类的方法。父类对象转换为子类对象抽象类 抽象类 抽象方法接口 特殊的抽象类,由常量和抽象方法组成。接口中的所有方法默认为公开抽象方法(public abstract),在类中实现接口的方法时,方法必须是public修饰。接口中的所有属性默认为公开静态常量(public static final)。接口与抽象类的区别
侵权处理QQ:3464097650--上传资料QQ:3464097650
【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。