面向对象程序设计高级.ppt
第3章 面向对象程序设计高级,郭建宏,椅子大戰,從前,有一間軟件小鋪,裡面有兩個程序員被指派去設計一個程序。壞心的老闆娘兼項目經理要求兩個人比賽,贏的人可以坐上象徵身份地位的AeronTM寶椅。程序開發高手阿珠和面向對象的信徒阿花兩個人都相信自己贏的可能性很大。,需求,在图形接口中画出四方形(squre),圆形(circle)和三角形(triangle),图形需要顺时针绕中心旋转,同时输出AIF音效文件。,阿珠是怎樣做的?,和以往一样,阿珠准备好开始设计重要的程序。没几下就写出了rotate和playSound方法。rotate()/绕中心旋转360度。playSound()/播放aif文件。,阿花是怎樣做的?,阿花分别为三个形状各写出一个类。,新的需求(一),前面的形状需要加上阿米巴原虫(Amoeba)形状。用户点选时也是旋转并播放.hif的声音文件。,阿珠该怎样做?,原来的rotate程序还可以用。但是playSound就得要修改。虽然修改的幅度不大,但是阿珠实在不想去碰已经测试过的程序代码。他应该很清楚,不管项目经理怎么保证,需求就是会不停的改。playSound(shapeNum)/参数用来标识传入的是否是amoeba图形/如果不是阿米巴形状,则播放.aif文件。/如果是则播放.hif文件,阿花該怎樣做?,阿花则写出一个新的类。面向对象让他最喜欢的其中一点就是有时不需改动已经测试好的程序就可以达成新的目标。面向对象的适应性和可扩展性让他面对修改时不会觉得太痛苦。,新的需求(二),阿米巴虫在旋转的时候需要以给定的作为原点旋转。,阿珠該怎樣做?,阿珠最好还是帮rotate程序加上轴心点的参数。这样就有一堆程序要改。本来已经测试好的东西全部又得重来一遍。rotate(shapeNum,xPt,yPt)/如果不是阿米巴,则绕中心旋转。/否则以xPt和yPt作为旋转中心旋转。,阿花该怎样做,阿花修改rotate这个方法,但不是每个都要修改,只修改Amoeba这个类而已。其他已经测试、编译过的部分完全没有必要修改。该类需要的修改就是加上旋转轴心点的属性。,问题的解决,从上面的分析可以看出,阿花的设计是非常好的。但是还有一个问题,在每个类中rotate和playSound有很多都是重复的。这样做太没有效率了。该怎样解决这样的问题呢?答案就是应用“继承”来解决。,怎樣繼承,继承概述,多个类中存在相同属性和行为时,将这些内容抽取到单独一个类中,那么多个类无需再定义这些属性和行为,只要继承单独的那个类即可。多个类可以称为子类,单独这个类称为父类或者超类。通过extends关键字让类与类之间产生继承关系。class SubDemo extends Demo子类继承父类后,都继承了父类的那些哪些成员呢?子类继承了父类的属性,包括私有属性。子类继承了除构造方法外的其他所有方法。问题:为什么子類對象在實例化之前必須首先調用父類中的構造方法之後再調用子類自己的構造方法?,继承的特点,Java只支持单继承,不支持多继承。一个类只能有一个父类,不可以有多个父类。class SubDemo extends Demo/okclass SubDemo extends Demo1,Demo2./error Java支持多层继承(继承体系)class Aclass B extends Aclass C extends B子类对象实例化子類對象在實例化之前必須首先調用父類中的構造方法之後再調用子類自己的構造方法。定义继承需要注意不要仅为了获取其他类中的某个功能而去继承。类与类之间要有所属(“is a”)的关系,xx1是xx2的一种。,阿米巴的rotate该怎么办?,阿米巴形状会需要完全不同的rotate和playSound程序,如果都继承Shape,那旋转的功能就都一样了。解决方法:Amoeba这个类可以覆盖(override)Shape的方法。(多态),阿米巴的rotate该怎么办?,方法覆写(Override),子类中出现与父类一模一样的方法时,会出现覆盖操作,也称为重写或者复写。父类中的私有方法不可以被覆盖。在子类覆盖方法中,继续使用被覆盖的方法可以通过“super.函数名”获取(super关键字部分介绍)。覆盖注意事项覆盖时,子类方法权限一定要大于父类方法权限。privateprotecteddefaultpublic静态只能覆盖静态。覆盖的应用当子类需要父类的功能,而功能主体子类有自己特有内容时,可以复写父类中的方法,这样,即沿袭了父类的功能,又定义了子类特有的内容。,重载和覆写的区别,继承的意义,继承的出现提供了代码的复用性。继承的出现让类与类之间产生了关系,提供了多态的前提。子类继承父类可以扩展已有类的功能。在工程中,父类一般都提供一个接口。(此问题在抽象类/接口部分解释),super关键字,this代表本类引用,super代表父类引用。super和this的用法相同。如果在子类中调用父类的同名方法,可以使用super关键字调用。当子类和父类出现同名成员的时候,可以使用super进行区分。子类要调用父类的构造方法的时候,可以使用super关键字调用。this和super都可以調用構造方法,但是兩者是不可以同時出現的,因為兩者調用構造時必須放在構造方法的首行。無論子類如何操作,最終必須要首先調用父類中的構造方法。super关键字最重要的作用就是用基类有参数的构造方法构造派生类的对象。,总结子类实例化过程,子类中所有的构造方法函数都会访问父类中空参数的构造函数。因为每一个构造函数的第一行都有一条默认的语句super();子类会具备父类中的数据,所以要先明确父类是如何对这些数据初始化的。当父类中没有空参数的构造函数时,子类的构造函数必须通过this或者super语句指定要访问的构造函数。,final关键字,final可以修饰类,方法,变量。final修饰的类不可以被继承。final修饰的方法不可以被覆盖。final修饰的变量是一个常量。只能被赋值一次。全局常量的声明使用static final關鍵字聯合聲明的變量稱為全局常量:public static final String INFO=“GJH”;内部类只能访问final修饰的局部变量。,椅子大战的新需求(三),现在需要重新定义各种形状旋转的度数圆形90度。矩形180度。三角形270度。阿米巴形不变。,需求分析,现在发现,rotate方法在父类中根本没有任何的作用,如果硬要写一些内容的话,不是太浪费了?所以最好的解决方案是在父类中只留一个声明,具体的实现放到子类中实现。要想这样实现就必须依靠“抽象类”。,抽象类概述,抽象定义:抽象就是从多个事物中将共性的,本质的内容抽取出来。例如:狼和狗共性都是犬科,犬科就是抽象出来的概念。抽象类:Java中可以定义没有方法体的方法,该方法的具体实现由子类完成,该方法称为抽象方法,包含抽象方法的类就是抽象类。抽象方法的由来:多个对象都具备相同的功能,但是功能具体内容有所不同,那么在抽取过程中,只抽取了功能定义,并未抽取功能主体,那么只有功能声明,没有功能主体的方法称为抽象方法。例如:狼和狗都有吼叫的方法,可是吼叫内容是不一样的。所以抽象出来的犬科虽然有吼叫功能,但是并不明确吼叫的细节。,抽象类的特点,抽象类和抽象方法必须用abstract关键字来修饰。抽象方法只有方法声明,没有方法体,定义在抽象类中。格式:修饰符 abstract 返回值类型 函数名(参数列表);抽象类不可以被实例化,也就是不可以用new创建对象。原因如下:抽象类是具体事物抽取出来的,本身是不具体的,没有对应的实例。例如:犬科是一个抽象的概念,真正存在的是狼和狗。而且抽象类即使创建了对象,调用抽象方法也没有意义。抽象类通过其子类实例化,而子类需要覆盖掉抽象类中所有的抽象方法后才可以创建对象,否则该子类也是抽象类。,抽象類的思考,問題1:一個抽象類可以使用final關鍵字嗎?問題2:一個抽象類中可以定義構造方法嗎?,回答,問題一:一個類如果使用了final關鍵字聲明,則此類不能被子類繼承,而抽象類又必須被子類覆寫,所以很明顯,第一個問題的答案是:“一個抽象類不能使用final關鍵字聲明”。問題二:實際上在一個抽象類中允許存在構造方法,因為抽象類依然使用的是類的繼承關係,而且抽象類中也存在各個屬性,所以子類在實例化之前一定要先對父類進行實例化。,抽象類總結,包含一個抽象方法的類必須是抽象類。抽象類和抽象方法都要使用abstract關鍵字聲明。抽象方法只可以聲明而不可以實現。抽象類使用的時候一定要有子類。子類仍然使用extends關鍵字繼承一個抽象類,同樣會存在單繼承的關係。一個子類不能同時繼承多個抽象類。子類(如果不是抽象類)必須覆寫抽象類中的全部抽象方法。抽象類中絕對不能使用final關鍵字聲明。抽象類中允許有構造方法,而且完全符合子類獨享的實例化過程。,椅子大战新的需求(四),现在将每一种形状播放的声音进行更改圆形播放cir文件的声音文件。四方形播放squ文件的声音文件。三角形播放tri文件的声音文件。阿米巴形不变。,需求分析,现在遇到了和抽象类中一样的问题,就是playSound方法在父类中也失去了作用,当然按照抽象类的方法可以将这个方法也声明为抽象方法。这个时候可以看出,父类中的所有的方法都是抽象方法了,这实际上就变成了一个“接口”。,接口的概念及定义,接口可以理解為一種特殊的類,裡面全部是由全局常量和公共的抽象方法組成。成员常量:public static final成员方法:public abstract接口的定義格式權限限定 interface 接口名稱 全局變量;抽象方法;,實現接口,與抽象類一樣,接口若要使用也必須通過子類,子類通過implements關鍵字實現接口。實現格式:public class 子類 implements 接口A,接口B,接口的出现将“多继承”通过另一种形式体现出来,即“多实现”,这就可以弥补Java在类的继承中只可以单继承的局限。,接口的特点,接口是对外暴露的规则。接口是程序的功能扩展。接口可以用来多实现。类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。接口与接口之间可以有继承关系。,椅子大战的编码需求(五),在客户端需要编写两个方法testPlaySound方法:可以测试所有形状的声音。testRotate方法:可以测试所有形状的旋转。,需求分析,按照以前的知识,要想实现前面的内容,就必须要写多个方法,那么如何实现一个方法可以接受不同形状的调用呢?解决方案就是使用面向对象中最重要的概念“多态”。,多态的概念,定义:某一类事物的多种存在形态。例:动物中猫,狗。猫这个对象对应的类型是猫类型猫 x=new 猫();同时猫也是动物中的一种,也可以把猫称为 动物。动物 y=new 猫();动物是猫和狗具体事物中抽取出来的父类型。父类型引用指向了子类对象,这实际上就是向上转型。,多态的概念,体现:父类或者接口的引用指向或者接收自己的子类对象。作用:多态的存在提高了程序的扩展性和后期可维护性。前提:需要存在继承或者实现关系。要有覆盖操作。,多态的特点,方法:编译时:要查看引用变量所属的类中是否有所调用的成员。在运行时:要查看对象所属的类中是否有所调用的成员。属性:只看引用变量所属的类。,椅子大战的新需求(六),需要在输出声音之前提示用户“即将开始播放声音”。需要在输出声音之后提示用户“声音播放已经结束”。需要在旋转之前提示用户“即将开始旋转”。需要在旋转之后提示用户“旋转已经结束”。,需求分析,按照以前的继续写的话有一个问题,就是需要重复编写四个方法的代码,这样就变得很浪费。但是如果要重新改成继承抽象方法,那么接口的一个重要的特点多继承就会失去,那么怎样可以更好的设计呢?答案就是将接口和抽象类一并使用。,面向对象设计的原则,一般的做法就是在类设计的顶层使用接口。然后设计一个抽象类实现接口,同时将重复的代码放入抽象类。其它的具体类继承抽象类。注意:一个具体类一定是叶子类。,