第10章 抽象类和接口.ppt
第第10章章 抽象类和接口抽象类和接口10.1引言10.2抽象类10.3日历类Calendar和公历类GregorianCanlendar10.4接口10.5将基本数据类型值处理为对象10.6基本类型和包装类之间的自动转换10.1 引言引言抽象类:将父类设计得非常抽象,让它包含所有子类的共同属性、方法,以至于它没有具体的实例。接口:实现多重继承10.2 抽象类抽象类l存在意义存在意义抽象类是类层次中较高层次的概括,抽象类的作用是让其他类来继承它的抽象化的特征抽象类中可以包括被它的所有子类共享的公共行为抽象类中可以包括被它的所有子类共享的公共属性在程序中不能用抽象类作为模板来创建对象;在用户生成实例时强迫用户生成更具体的实例,保证代码的安全性l抽象类的格式抽象类的格式abstract class 类名类名 l抽象方法的语法形式为抽象方法的语法形式为abstract(.);l抽象方法的优点抽象方法的优点隐藏具体的细节信息,所有的子类使用的都是相同的方法头,其中包含了调用该方法时需要了解的全部信息强迫子类完成指定的行为,规定其子类需要用到的“标准”行为通用程序设计(一般程序设计)例例1问:抽象类问:抽象类GeometricObject中的中的抽象方法可否删除?抽象方法可否删除?l各种图形都需要实现绘图方法各种图形都需要实现绘图方法,可在抽象父类中声明一个可在抽象父类中声明一个draw抽象方法抽象方法abstractclassGraphicObjectintx,y;voidmoveTo(intX,intY).abstractvoiddraw();l然后在每一个子类中重写然后在每一个子类中重写draw方法,例如:方法,例如:classCircleextendsGraphicObjectvoiddraw().classRectangleextendsGraphicObjectvoiddraw().publicclassTestpublicstaticvoidmain()GraphicObjectob1=Cirlce();GraphicObjectob2=Cirlce();ob1.draw();ob2.draw();例例2l将所有图形的公共属性及方法抽象到抽象类将所有图形的公共属性及方法抽象到抽象类Shape。再将。再将2D及及3D对象的特性分别抽取出来,形成两个抽象类对象的特性分别抽取出来,形成两个抽象类TwoDimensionalShape及及ThreeDimensionalShape2D图形包括Circles、Triangles、Rectangles和Squares3D图形包括Cube、Sphere、或Tetrahedron在UML中,抽象类的类名为斜体斜体,以与具体类相区别ShapeCircleTriangleRectangleSquareTwoDimensionalShapeThreeDimensionalShapeCubeSphereTetrahedron例例3LoanLeaseMortgageHouseLoanCarLoanl贷款贷款(Loan)分为许多种类,如租借分为许多种类,如租借(Lease)、抵押抵押(Mortgage)、房屋贷款房屋贷款(HouseLoan)、汽车贷款汽车贷款(CarLoan)等等l将将Loan声明为抽象类,并指定所有的子类对象都应具有的行声明为抽象类,并指定所有的子类对象都应具有的行为,如计算月还款值为,如计算月还款值(calculateMonthlyPayment),还款还款(makePayment),取得客户信息取得客户信息(getClientInfo),其中前两其中前两个因贷款种类不同计算方法也不同,可声明为抽象方法,个因贷款种类不同计算方法也不同,可声明为抽象方法,Loan的所有子类都必须对这两个抽象方法进行重写的所有子类都必须对这两个抽象方法进行重写publicabstractclassLoanpublicabstractfloatcalculateMonthlyPayment();publicabstractvoidmakePayment(floatamount);publicClientgetClientInfo()例例4l注意注意:1抽象类前需加修饰符abstract2不能使用new方法进行实例化,故,抽象类必须被继承3抽象类可包含常规类能够包含的任何东西,例如构造方法等非抽象方法,其构造方法在子类的构造方法中调用4没有抽象方法的类也可被声明为抽象类5包含抽象方法的类必须声明为抽象类6若子类没有实现父类的全部抽象方法,它也必须声明为抽象类7抽象方法必须是非静态的,子类中的实现也必须是非静态的,否则无法覆盖8即便父类是具体类,子类也可能是抽象类9抽象类虽然无法用new实例化,但可以用作数据类型例:抽象类x;抽象类a5=new抽象类5;x=new子类();ai=new子类();10.3 日历类日历类Calendar和公历和公历类类GregorianCanlendar10.4 接口接口1.Java不支持多重继承,是为了使语言本身结构简单,层次清不支持多重继承,是为了使语言本身结构简单,层次清楚,易于管理,更安全可靠,避免冲突。但同时也就限制了楚,易于管理,更安全可靠,避免冲突。但同时也就限制了语言的功能。语言的功能。2.为了在实际应用中借助多重继承的功能,共享一些公用的常为了在实际应用中借助多重继承的功能,共享一些公用的常量和一些常用的方法,量和一些常用的方法,Java使用接口来弥补。使用接口来弥补。一个类可以实一个类可以实现多个接口,达到多重继承的效果现多个接口,达到多重继承的效果。3.接口可以看作是接口可以看作是常量常量和和没有实现的方法没有实现的方法的集合。的集合。4.接口与抽象类相似,接口中的方法只是做了声明,而没有定接口与抽象类相似,接口中的方法只是做了声明,而没有定义任何具体的操作方法。义任何具体的操作方法。声明接口的格式修饰符interface接口名/*常量*/*抽象方法*/方法自动为方法自动为public abstract变量自动为变量自动为public static finalpublicinterfaceComparablepublicintcompareTo(Object);例如packagejava.langpublicfinalclassStringextendsObjectimplementsSerializable,Comparable,CharSequencepublicintcompareTo(StringanotherString)publicclassDateextendsObjectimplementsSerializable,Cloneable,ComparablepublicintcompareTo(DateanotherDate)类java.lang.String和Java.util.Date都实现了Comparable接口右边的表达式都成立sinstanceofStringsinstanceofObjectsinstanceofCpareTo(“china”)返回0“china”.compareTo(s)返回0“china”.compareTo(“japan”)返回-7publicclassMaxpublicstaticComparablemax(Comparableo1,Comparableo2)if(pareTo(o2)0)returno1;elsereturno2;应用:例如StringmaxString=(String)Max.max(s,”japan”)若Strings=“china”;应用例如P277的图a和图b问:为什么说图a更鲁棒?l接口接口与抽象类一样都是定义多个类的共同属性使抽象的概念更深入了一层,是一个“纯”抽象类,它只提供一种形式,并不提供实现允许创建者规定方法的基本形式:方法名、参数列表以及返回类型,但不规定方法主体。方法自动为publicabstract也可以包含基本数据类型的数据成员,但它们都自动为publicstaticfinall接口允许我们在看起来不相干的对象之间接口允许我们在看起来不相干的对象之间定义共同行为定义共同行为l接口的作用接口的作用是面向对象的一个重要机制实现多继承,同时免除C+中的多继承那样的复杂性建立类和类之间的“协议”l把类根据其实现的功能来分别代表,而不必顾虑它所在的类继承层次;这样可以最大限度地利用动态绑定,隐藏实现细节l实现不同类之间的常量共享l接口的语法接口的语法声明格式为publicinterface接口名称extends父接口名/方法的原型声明或静态常量接口的数据成员一定要赋初值,且此值将不能再更改,允许省略publicstaticfinal关键字接口中的方法必须是“抽象方法”,不能有方法体,允许省略publicabstract关键字接口也可以继承接口的实现l接口的实现接口的实现接口不能用new运算符直接产生对象,必须利用其特性设计新的类,再用新类来创建对象利用接口设计类的过程,称为接口的实现,使用implements关键字语法如下public class 类名称 implements 接口名称 /*Bodies for the interface methods*/*Own data and methods.*/l必须实现接口中的所有方法l实现接口的方法必须声明成public例例1l声明一个接口声明一个接口Shape2D,可利用它来实现二维的几何可利用它来实现二维的几何形状类形状类Circle和和Rectangle把计算面积的方法声明在接口里pi值是常量,把它声明在接口的数据成员里interfaceShape2D/声明Shape2D接口finaldoublepi=3.14;/数据成员一定要初始化publicabstractdoublearea();/抽象方法在接口的声明中,允许省略一些关键字,也可声明如下interfaceShape2Ddoublepi=3.14;doublearea();例例2classCircleimplementsShape2Ddoubleradius;publicCircle(doubler)radius=r;publicdoublearea()return(pi*radius*radius);classRectangleimplementsShape2Dintwidth,height;publicRectangle(intw,inth)width=w;height=h;publicdoublearea()return(width*height);l声明声明Circle与与Rectangle两个类实现两个类实现Shape2D接口接口l测试类测试类publicclassInterfaceTesterpublicstaticvoidmain(Stringargs)Rectanglerect=newRectangle(5,6);System.out.println(Areaofrect=+rect.area();Circlecir=newCircle(2.0);System.out.println(Areaofcir=+cir.area();l运行结果运行结果Areaofrect=30.0Areaofcir=12.56l声明接口类型的变量,并用它来访问对象声明接口类型的变量,并用它来访问对象publicclassVariableTesterpublicstaticvoidmain(Stringargs)Shape2Dvar1,var2;var1=newRectangle(5,6);System.out.println(Areaofvar1=+var1.area();var2=newCircle(2.0);System.out.println(Areaofvar2=+var2.area();l输出结果输出结果Areaofvar1=30.0Areaofvar2=12.56l多重继承多重继承Java的设计以简单实用为导向,不允许一个类有多个父类但允许一个类可以实现多个接口,通过这种机制可实现多重继承一个类实现多个接口的语法如下类修饰符class类名称implements接口1,接口2,lCar类可以实现接口类可以实现接口Insurable,Drivable,SellablepublicclassCarimplementsInsurable,Drivable,Sellable.例例3l声明声明Circle类实现接口类实现接口Shape2D和和ColorShape2D具有pi与area()方法,用来计算面积Color则具有setColor方法,可用来赋值颜色通过实现这两个接口,Circle类得以同时拥有这两个接口的成员,达到了多重继承的目的interfaceShape2D/声明Shape2D接口finaldoublepi=3.14;/数据成员一定要初始化publicabstractdoublearea();/抽象方法interfaceColorvoidsetColor(Stringstr);/抽象方法例例4classCircleimplementsShape2D,Color/实现Circle类doubleradius;Stringcolor;publicCircle(doubler)/构造方法radius=r;publicdoublearea()/定义area()的处理方式return(pi*radius*radius);publicvoidsetColor(Stringstr)/定义setColor()的处理方式color=str;System.out.println(color=+color);l测试类测试类publicclassMultiInterfaceTesterpublicstaticvoidmain(Stringargs)Circlecir;cir=newCircle(2.0);cir.setColor(blue);System.out.println(Area=+cir.area();l输出结果输出结果color=blueArea=12.56l接口的多重扩展接口的多重扩展接口可通过扩展的技术派生出新的接口l原来的接口称为基本接口(baseinterface)或父接口(superinterface)l派生出的接口称为派生接口(derivedinterface)或子接口(subinterface)派生接口不仅可以保有父接口的成员,同时也可加入新成员以满足实际问题的需要实现接口的类也必须实现此接口的父接口接口扩展的语法interface子接口的名称extends父接口1,父接口2,接口的扩展接口的扩展public interface I1public void m1();public interface I2 extends I1public void m2();public interface I3 public void m3();public class A implements I2,I3 public void m1()/implementspublic void m2()/implementspublic void m3()/implementsI1.javaI2.javaI3.javaA.java当一个类实现多个接口时,这个类可以是多种类型的实例。如下列表达式都返回trueA a=new A();a instanceof I1a instanceof I2a instanceof I3a instanceof ObjectI1 i1=new A();I2 i2=new A();I3 i3=new A();Cloneable接口接口lJava定义了定义了Cloneable接口,任何想实现克隆功能的类必须接口,任何想实现克隆功能的类必须实现该接口,同时改写从实现该接口,同时改写从Object类继承的类继承的clone方法,并将访方法,并将访问属性改为问属性改为publicl但但Cloneable接口为空接口,其定义为接口为空接口,其定义为package java.lang;public interface Cloneable l空接口称为标记接口空接口称为标记接口(markup interface)l空接口唯一作用:允许用空接口唯一作用:允许用instanceof检查对象的类型:检查对象的类型:if(obj instanceof Cloneable)protected native Object clone()throws CloneNotSupportedException;Java.lang.Object类中有类中有classAimplementsCloneableprotectedAclone()tryreturn(A)super.clone();catch(CloneNotSupportedExceptionex)returnnull;publicclassTpublicstaticvoidmain(Strings)Aa1=newA();Aa2=a1.clone();想用clone类A需要:(1)实现Cloneable(2)覆盖Object中的clone()方法至少是protected返回的是A,是Object的子类,也能覆盖classAimplementsCloneableprotectedAclone()throwsCloneNotSupportedExceptionreturn(A)super.clone();publicclassTpublicstaticvoidmain(Strings)throwsCloneNotSupportedExceptionAa1=newA();Aa2=a1.clone();classBclassAextendsBimplementsCloneableprotectedAclone()throwsCloneNotSupportedExceptionreturn(A)super.clone();publicclassTpublicstaticvoidmain(Strings)throwsCloneNotSupportedExceptionBa1=newA();Aa2=a1.clone();编译错。B类没有实现Cloneable接口,没有重写clone()方法何时用抽象类?何时用接口?抽象类:“强是一种关系”类继承接口:“弱是一种关系”不同类的对象共有的属性、行为动物哺乳动物非哺乳动物电器家用电器非家用电器寿命P278接口与抽象类变量变量new实实例化例化构造构造方法方法具体具体方法方法抽象方法抽象方法其它方法其它方法抽象抽象类类无限制无限制否否有,有,由子由子类可类可调用调用可以可以有有子类若具子类若具体,必须体,必须实现全部实现全部抽象方法抽象方法无限制无限制接口接口隐含隐含public static final否否无无不能不能有有子类必须子类必须实现全部实现全部抽象方法抽象方法隐含隐含public abstract10.5 将基本数据类型值处理为对象将基本数据类型值处理为对象DoubledObject=newDouble(5.0);IntegeriObject=newInteger(1);longl=dObject.longValue();inti=iObject.intValue();ComparableObjectNumberCharacterBooleanDoubleFloatLongIntegerShortByte10.6 基本类型和包装类之间的基本类型和包装类之间的自动转换自动转换IntegerintObject=2;等价于IntegerintObject=newInteger(2);IntegeriArray=1,2,3;自动执行了IntegeriObject=Integer.valueOf(“12”);/字符串变整数并构建对象System.out.println(iArray0)中,自动将iArray0转换为int类型Integer.parseInt(“12”)/返回12,字符串转换成整数Double.parseDouble(“12.3”)/返回12.3,字符串转换成double型iArray0=newInteger(1);iArray1=newInteger(2);iArray2=newInteger(3);