第八章 继承、抽象类和接口.ppt
第八章 继承、抽象类和接口本章主要内容n子类的创建n在子类中访问父类成员n覆盖父类的方法n抽象类和抽象方法n接口及接口的实现n利用接口实现类的多重继承n内部类的匿名类n包(类库)继承n继承是一种由已有类创建新类的机制。n利用继承,可以先创建一个公共属性的一般类,根据一般类在创建一个具有特殊属性的新类。n新类继承一般类的状态和行为,并根据需要增加自己的新的状态和行为。多层继承多层继承Person 类类Student 类类Worker类类小学生小学生 类类中学生中学生 类类 大学生大学生 类类 IT业业 工人类工人类其他业其他业 工人类工人类IT-java-类类IT-C-类类IT业业 其他其他 类类8.1 类的继承n一个类从另一个类派生出来的过程叫继承n被继承的类称为基类(超类)n执行该继承的类称为子类(派生类)v继承是面向对象编程技术的一块基继承是面向对象编程技术的一块基石,它允许创建分等级层次的类。石,它允许创建分等级层次的类。v运用继承,可以创建一个通用类定运用继承,可以创建一个通用类定义一系列一般特性。该类可以被更具义一系列一般特性。该类可以被更具体的类继承体的类继承vPersonPerson是父类;定义了是父类;定义了name/agename/age两个两个属性,属性,getInfogetInfo()()方法方法vStudent/Student/WorderWorder分别是其的两个子分别是其的两个子类,除了已有的类,除了已有的name/age/name/age/getInfogetInfo以外,以外,还有自己的特有的属性和方法还有自己的特有的属性和方法PersonString nameint ageString getInfo()StudentString nameint ageString schoolString getInfo()String getSchool()WorkerString nameint ageString CompanyString getInfo()String getCompany()继承继承继承的实现继承的实现n通过extends关键字来实现类间的继承关系n声明一个继承父类的类的通常形式如下:qclass subclass-name extends superclass-name /类体类体 注意注意:没有extends,默认父类为java.lang.Object只能有一个父类,即单继承子类继承父类的全部成员(方法和属性),除private的成员/方法和父类的构造方法classPersonprivateStringname;privateintage;publicPerson()System.out.println(调用了人类的构造方法Person());publicvoidSetNameAge(Stringname,intage)this.name=name;this.age=age;publicvoidshow()System.out.println(姓名:+name+年龄:+age);classStudentextendsPersonprivateStringdepartment;publicStudent()System.out.println(调用了学生类的构造方法Student();publicvoidSetDepartment(Stringdep)department=dep;System.out.println(我是+department+的学生);publicclassapp8_1publicstaticvoidmain(Stringargs)Studentstu=newStudent();stu.SetNameAge(张小三,21);stu.show();stu.SetDepartment(计算机科学系);nJava程序在执行子类的构造方法之前,会先自动调用父类中没有参数的构造函数,其目的是为了帮助继承自父类的成员做初始化的操作。调用父类中特定的构造函数class Person private String name;private int age;public Person()System.out.println(调用了人类的构造方法调用了人类的构造方法Person()());public Person(String name,int age)System.out.println(调用了人类的构造方法调用了人类的构造方法Person()());this.name=name;this.age=age;public void show()System.out.println(姓名:姓名:+name+年龄:年龄:+age);classStudentextendsPersonprivateStringdepartment;publicStudent()System.out.println(调用了学生类的构造方法Student();publicStudent(Stringname,intage,Stringdep)super(name,age);department=dep;System.out.println(我是+department+的学生);System.out.println(“调用了学生类的有参构造方法Student(Stringname,intage,Stringdep);publicclassapp8_1publicstaticvoidmain(Stringargs)Studentstu=newStudent();/调用父类的无参构造函数stu.show();Studentstu2=newStudent(张小三,21,计算机科学系);/调用父类的有参构造函数stu2.show();super用来引用当前对象的父类,this用来引用当前对象,注意n调用父类构造方法的super()语句必须写在子类构造方法的第一行,否则编译时出错。n在子类中访问父类的构造方法,其格式为super(参数列表),super()可以重载。nJava程序在执行子类的构造方法之前,如果没有super()调用父类中特定的构造方法,则会先调用父类中“没有参数的构造方法”。nsuper()是从子类的构造方法调用父类的构造方法,而this()是在一个类内部调用其他的构造方法。nsuper()和this()必须放在构造方法内的第一行,并且super()和this()不能同时存在一个构造方法内。n在静态方法不能使用super()和this()。在子类中访问父类的成员n使用使用super可以可以访问父类的构造方法访问父类的构造方法,还可以,还可以访问父类的成员变量和成员方法访问父类的成员变量和成员方法,但,但不能访问不能访问在子类中添加的成员。在子类中添加的成员。nsuper.变量名变量名nsuper.方法名方法名classPersonprotectedStringname;protectedintage;publicPerson()System.out.println(调用了人类的构造方法Person());publicPerson(Stringname,intage)System.out.println(调用了人类的构造方法Person());this.name=name;this.age=age;publicvoidshow()System.out.println(姓名:+name+年龄:+age);classStudentextendsPersonprivateStringdepartment;intage=20;publicStudent(Stringxm,Stringdep)name=xm;department=dep;super.age=25;System.out.println(子类Student中的成员变量age:+age);super.show();System.out.println(系别+department);publicclassapp8_3publicstaticvoidmain(Stringargs)Studentstu=newStudent(李小双,计科系);classStudentextendsPersonprivateStringdepartment;intage=20;/子类的成员变量publicStudent(Stringxm,Stringdep)super.name=xm;department=dep;age=3;super.age=25;/父类的成员变量System.out.println(子类Student中的成员变量age:+age);super.show();System.out.println(系别+department);classPersonprotectedStringname;protectedintage;n无法在子类(类外)访问父类中的private成员n将父类中的成员声明为protected(保护成员),则可以在父类中直接访问,也可以在其子类中访问。覆盖n重载重载是指在是指在同一类同一类中定义名称相同,但参数个中定义名称相同,但参数个数或类型不同的方法。数或类型不同的方法。n覆盖覆盖是指在是指在子类中,定义名称、参数个数、类子类中,定义名称、参数个数、类型与父类完全相同的方法,型与父类完全相同的方法,用以重写父类里同用以重写父类里同名方法的功能。名方法的功能。v 覆盖和重载是覆盖和重载是JAVAJAVA中实中实现多态性的两种方法现多态性的两种方法覆盖父类的方法n子类继承父类中所有可被访问的成员方法时,如果子类的方法与父类的方法同名,则不能继承,此时子类的方法覆盖父类的方法。n子类中不能覆盖父类中声明为final或static的方法。classPersonprotectedStringname;protectedintage;publicPerson(Stringname,intage)this.name=name;this.age=age;protectedvoidshow()System.out.println(姓名:+name+年龄:+age);classStudentextendsPersonprivateStringdepartment;publicStudent(Stringname,intage,Stringdep)super(name,age);department=dep;protectedvoidshow()System.out.println(系别+department);publicclassapp8_4publicstaticvoidmain(Stringargs)Studentstu=newStudent(李小双,20,计科系);stu.show();n注意点:q如果在子类中想调用父类中的那个被重写的方法,我们可以用super.方法的格式。q重写方法时,不能使用比父类中被重写的方法更严格的访问权限。npublic-protected-default-private(高到低)用父类的变量访问子类的成员n通过父类的变量访问子类的成员,只限于“覆盖”的情况发生时。不可被继承的成员与最终类final关键字关键字nJava中声明类、属性和方法时,可使用关键字final来修饰。qfinal标记的类不能被继承最终类。qfinal标记的方法不能被子类覆盖。qfinal标记的变量(成员变量或局部变量)即成为常量,只能赋值一次。qpublicstaticfinal共同标记常量时,这个常量就成了全局的常量。npublicstaticfinalintMAXCOUNT=10;nfinalStingNAME=“SUN”;v finalfinal标明某一个对象标明某一个对象(类,属性,方法)是(类,属性,方法)是固定不变的。固定不变的。finalclassAAAstaticfinaldoublepi=3.14;publicfinalvoidshow()System.out.println(pi=+pi);classBBBextendsAAAprivateintnum=100;publicvoidshow()System.out.println(num=+num);publicvoidchange()super.pi=5;publicclassapp8_6publicstaticvoidmain(Stringargs)BBBex=newBBB();ex.show();ex.change();Object类nObject类是java中所有类顶级父类。q如果一个类没有明显的使用extends继承另一个父类,则默认是继承了Object类。qObject类中的方法如果在子类没有被覆盖的话,则默认使用的是Object中的方法。Object类常用方法方法功能publicBooleanequals(Objectobj)判断两个对象变量所指的是否为同一个对象publicStringtoString()将调用toString()方法的对象转换成字符串publicfinalClassgetClass()返回调用getClass()方法的对象所属的类protectedObjectclone()返回调用该方法的对象的一个副本classAinta=1;publicclassapp8_7publicstaticvoidmain(Stringargs)Aobj1=newA();Aobj2=newA();Strings1,s2,s3=abc,s4=abc;s1=newString(abc);s2=newString(abc);System.out.println(s1.equals(s2)是+(s1.equals(s2);System.out.println(s1=s3是+(s1=s3);System.out.println(s1.equals(s3)是+(s1.equals(s3);System.out.println(s3=s4是+(s3=s4);System.out.println(s2.equals(s3)是+(s2.equals(s3);System.out.println(s1=s2是+(s1=s2);System.out.println(obj1=obj2是+(obj1=obj2);System.out.println(obj1.equals(obj2)是+obj1.equals(obj2);obj1=obj2;System.out.println(obj1=obj2是+(obj1=obj2);System.out.println(obj1.equals(obj2)是+obj1.equals(obj2);“=”用于比较两个变量本身的值,即两个对象在内存中的地址用于比较两个变量本身的值,即两个对象在内存中的地址“=”和和“equals()()”对于非字符串类型的变量来说比较在堆内存的对于非字符串类型的变量来说比较在堆内存的首地址;用来比较两个类变量时,比较两个类变量是否指向同一个对象首地址;用来比较两个类变量时,比较两个类变量是否指向同一个对象classPersonprotectedStringname;publicPerson(Stringxm)name=xm;publicclassapp8_8publicstaticvoidmain(Stringargs)Personper=newPerson(张三);Classobj=per.getClass();System.out.println(对象per所属的类为:+obj);n语法格式:q对象instanceof类(或接口)n返回值为布尔值,真true或假false;qStrings=“abc”;nIf(sinstanceofString)qPersonp=newPerson();npinstanceofPersonqStudentstu=newStudent();nstuinstanceofStudent对象运算符instanceofinstanceofinstanceof 操作符可以用操作符可以用操作符可以用操作符可以用它来判断一个实例对象它来判断一个实例对象它来判断一个实例对象它来判断一个实例对象是否属于一个类是否属于一个类是否属于一个类是否属于一个类npublicclassPersonnnstaticintcount=0;nprotectedStringname;nprotectedintage;npublicPerson(Strings1,inta1)nnname=s1;nage=a1;nthis.count+;nnpublicStringtoString()nnreturnthis.name+,+this.age;nnpublicvoiddisplay()nnSystem.out.print(本类名=+this.getClass().getName()+;);nSystem.out.println(本类名=+this.getClass().getSuperclass().getName()+;);nSystem.out.print(Person.count+this.count+);nSystem.out.print(Student.count+Student.count+);nObjectobj=this;nif(objinstanceofPerson)nSystem.out.print(obj.toString()+是Person的对象);nnnclassStudentextendsPersonnnstaticintcount=0;nprotectedStringdept;nprotectedStudent(Stringn1,inta1,Stringd1)nnsuper(n1,a1);ndept=d1;nthis.count+;nnpublicStringtoString()nnreturnsuper.toString()+,+dept;nnpublicvoiddisplay()nnsuper.display();nSystem.out.print(super.count+super.count);nSystem.out.print(this.count+this.count);nnpublicstaticvoidmain(Stringargs)nPersonper=newPerson(王永泰,23);nper.display();nStudentstu=newStudent(李小双,20,计科系);nstu.display();nnn可以通过当前对象this调用Object类中的getClass()方法,得到当前对象所在的类,在调用Class中getName()方法得到this的类名字符串。抽象类n为什么存在?n父类的方法具有不确定性n如何解决?n当父类中的一些方法不能确定,可以用abstract来修饰该方法抽象方法,用abstract来修饰类抽象类8.2 抽象类专门用作父类n格式abstract class类名类名声明成员变量;声明成员变量;返回类型返回类型 方法名(参数表)方法名(参数表)abstract返回类型返回类型 方法名(参数表)方法名(参数表);抽象方法,是以关键字开头的方法,此方法只声明返回类型,方法名称与参数,但是没有方法体,以“;”结尾。抽象方法必须被子类的方法所覆盖,static和abstract不能同时方法n抽象类的特点:q抽象类抽象类不能直接运用不能直接运用new创建对象创建对象q抽象类的实体中可以有抽象类的实体中可以有abstract方法,且方法,且abstract方法只允许方法只允许声明,而不允许实现声明,而不允许实现nabstract returnType method(paramList);q抽象类中抽象类中不一定要包含不一定要包含abstract方法方法,但,但一个类中包含了一个类中包含了abstract方法方法,则这个类必须声明为,则这个类必须声明为abstract类。类。q抽象类的实现抽象类的实现子类必须实现抽象类中所有的子类必须实现抽象类中所有的abstract方法方法q声明类时,声明类时,abstract和和final不能同时使用不能同时使用q声明方法时,声明方法时,abstract不能与不能与private、static、final和和native同时使用同时使用abstractclassAabstractvoidprint();classBextendsAvoidprint()publicstaticvoidmain(Stringargs)Bb=newB();抽象类的应用abstractclassShape/抽象类protectedStringname;publicShape(Stringxm)name=xm;System.out.print(名称:+name);abstractpublicdoublegetArea();abstractpublicdoublegetLength();/抽象方法classCircleextendsShapeprivatedoublepi=3.14;privatedoubleradius;publicCircle(Stringshapename,doubler)super(shapename);/调用抽象类的构造方法radius=r;publicdoublegetArea()/实现抽象类中的方法returnpi*radius*radius;publicdoublegetLength()/实现抽象类中的方法return2*pi*radius;classRectangleextendsShapeprivatedoublewidth;privatedoubleheight;publicRectangle(Stringshapename,doublewidth,doubleheight)super(shapename);this.width=width;this.height=height;publicdoublegetArea()/抽象类的实现子类必须实现抽象类中所有的abstract方法returnwidth+height;publicdoublegetLength()return2*height*width;publicclassapp8_10publicstaticvoidmain(Stringargs)Shaperect=newRectangle(长方形,6.5,10.3);/因为覆盖了父类中的方法,可以用父类的变量访问子类的成员System.out.print(;面积=+rect.getArea();System.out.println(;周长=+rect.getLength();Shapecircle=newCircle(圆,6.5);System.out.print(;面积=+circle.getArea();System.out.print(;周长=+circle.getLength();接口n现实生活中的接口nUsb接口n软件中的接口给出一些没有内容的方法,封装到一起,到每个类要使用的时候,在更具具体情况把这些方法写出来。8.3 接口n接口(接口(interface),是用来实现类间),是用来实现类间多重继承多重继承的结构模式。的结构模式。n接口和抽象类的区别接口和抽象类的区别q1、接口是常量和抽象方法的集合(接口是常量和抽象方法的集合(接口只包接口只包含常量和方法的定义含常量和方法的定义,没有变量和方法的实现。),没有变量和方法的实现。)q2、接口里的方法必须接口里的方法必须全部声明为全部声明为abstract。定义publicinterface接口名称extends父接口列表/声明常量字段,必须赋初值。publicstaticfinal数据类型成员变量名=常量;publicabstract返回值的数据类型方法名(参数名);修饰符只能为public或缺省;public;接口能被任何类成员访问。缺省时使用默认的访问控制,即接口只能被与它在同一包中的成员访问。接口中的变量必须为接口中的变量必须为public static final,不,不能使用能使用private,protected接口的方法必须为接口的方法必须为public abstract,只,只进行方法声明,进行方法声明,不提供方法的实现不提供方法的实现interfaceIShapefinaldoublepi=3.14;abstractdoublegetArea();abstractdoublegetLength();IShapes=newIShape();/接口不能直接建立对象,必须通过建立一个新类来实现接口,在利用类来创建对象implementsClassCirleimplementsIShape接口的实现n接口由类实现接口由类实现,类可以在继承父类的同时实现多个接口。,类可以在继承父类的同时实现多个接口。n类实现接口时类实现接口时,必须实现接口中的所有方法,必须实现接口中的所有方法,为这些方,为这些方法提供方法体。法提供方法体。且方法必须声明为且方法必须声明为public,返回类型和,返回类型和参数必须和接口中声明一致。参数必须和接口中声明一致。n类实现接口时,类实现接口时,每个方法必须有方法体每个方法必须有方法体,如果不能实现,如果不能实现某个方法某个方法,也必须写出一个空方法,也必须写出一个空方法。n如果接口的方法的返回类型不是如果接口的方法的返回类型不是void的,则在类中实现的,则在类中实现 该接口方法是,该接口方法是,方法体至少要有一个方法体至少要有一个return语句。语句。classCircleimplementsIShape/Circle实现IShape接口doubleradius;publicCircle(doubler)radius=r;publicdoublegetArea()returnpi*radius*radius;publicdoublegetLength()return2*pi*radius;classRectangleimplementsIShapeprivatedoublewidth;privatedoubleheight;publicRectangle(doublewidth,doubleheight)this.width=width;this.height=height;publicdoublegetArea()returnwidth*height;publicdoublegetLength()return2*(width+height);publicclassapp8_11publicstaticvoidmain(Stringargs)IShapecircle=newCircle(5.0);/circle指的是接口的变量,指向了实现类的对象System.out.print(圆面积为+circle.getArea();System.out.println(;周长为+circle.getLength();Rectanglerect=newRectangle(6.5,10.8);System.out.print(矩形面积为+rect.getArea();System.out.println(;周长为+rect.getLength();接口的继承n接口也有接口也有继承性(可以继承其他的接口,但是不继承性(可以继承其他的接口,但是不能继承其他的类)能继承其他的类)n定义一个接口时可通过定义一个接口时可通过extends关键字声明该新关键字声明该新接口是某个一存在父接口的派生接口,它将继承接口是某个一存在父接口的派生接口,它将继承父接口的所有变量与方法。父接口的所有变量与方法。n一个接口可以一个接口可以有一个以上的父接口有一个以上的父接口,它们之间用,它们之间用逗号分隔,形成父接口列表。逗号分隔,形成父接口列表。n如果子接口中定义了与父接口同名的常量或者相如果子接口中定义了与父接口同名的常量或者相同的方法,则父接口中的常量和方法被同的方法,则父接口中的常量和方法被覆盖覆盖。ninterfaceusbnninta=1;npublicabstractvoidstart();npublicabstractvoidstop();nnclassCameraimplementsusbnnpublicvoidstart()nnSystem.out.println(我是相机,开始工作了);npublicvoidstop()nnSystem.out.println(我是相机,停止工作了);nnclassPhoneimplementsusbnnpublicvoidstart()nnSystem.out.println(我是手机,开始工作了);npublicvoidstop()nnSystem.out.println(我是手机,停止工作了);nnclassComputerpublicvoiduseUsb(usbusb1)/usbusb1是接口的变量,实参可以是实现接口类的对象usb1.start();usb1.stop();publicclasstest3publicstaticvoidmain(Stringargs)Computercomputer1=newComputer();Cameracamera1=newCamera();Phonephone1=newPhone();computer1.useUsb(camera1);computer1.useUsb(phone1);interfaceface1doublepi=3.14;abstractdoublearea();interfaceface2abstractvoidsetColor(Stringc);interfaceface3extendsface1,face2abstractvoidvolume();public class Cylinder implements face3 private double radius;private int height;protected String color;public Cylinder(double r,int h)radius=r;height=h;public double area()return pi*radius*radius;public void setColor(String c)color=c;System.out.println(黑色黑色+color);public void volume()System.out.println(圆柱体体积圆柱体体积=+area()*height);public static void main(String args)Cylinder volu=new Cylinder(3.0,2);volu.setColor(红色红色);volu.volume();利用接口实现多重继承n一个类实现多个接口时,在implements字句中用逗号分隔各个接口名。interfaceface1doublepi=3.14;abstractdoublearea();interfaceface2abstractvoidsetColor(Stringc);interfaceface3abstractvoidvolume();publicclassCylinderimplementsface1,face2,face3privatedoubleradius;privateintheight;protectedStringcolor;publicCylinder(doubler,inth)radius=r;height=h;publicdoublearea()returnpi*radius*radius;publicvoidsetColor(Stringc)color=c;System.out.println(黑色+color);publicvoidvolume()System.out.println(圆柱体体积=+area()*height);publicstaticvoidmain(Stringargs)Cylindervolu=newCylinder(3.0,2);volu.setColor(红色);volu.volume();1、关于Java的修饰符,以下说法错误的是()。A抽象类中的方法不一定都是抽象方法Bfinal类中的属性和方法都必须被final修饰符修饰C类及其属性、方法可以同时有一个以上的修饰符来修饰D要使类中某个成员变量只能被它自身访问到,该变量只能用private修饰在使用interface声明一个接口时,只可以使用()修饰符修饰该接口。A、privateB、protectedC、privateprotectedD、public类ABC定义如下:1publicclassABC2publicintmax(inta,intb)34将以下哪个方法插入行3是不合法的。()A、publicfloatmax(floata,floatb,floatc)B、publicdoublemax(intc,intd)C、publicfloatmax(floata,floatb)D、privateintmax(inta,intb,intc)35、以下哪个接口的定义是正确的?()A.interfaceBvoidprint();B.abstractinterfaceBvoidprint();C.abstractinterfaceBextendsA1,A2abstractvoidprint();D.interfaceBvoidprint();37、A派生出子类B,B派生出子类C,并且在Java源代码中有如下声明:Aa0=newA();Aa1=newB();Aa2=newC();问以下哪个说法是正确的?()A、只有第1行能通过编译 B、第1、2行能通过编译,但第3行编译出错C、第1、2、3行能通过编译,但第2、3行运行时出错D、第1行、第2行和第3行的声明都是正确的以下方法的返回类型是()。ReturnTypefunction(intx,doubley)returnx+y/2;AbyteBshortCfloatDdouble写出以下程序的运行结果。classStaticStuffstaticintx;staticx+=7;publicstaticvoidmain(Stringargs)System.out.println(x=+x);staticx%=4;x=38.4 内部类与匿名类n内部类(InnerClass)是定义在类中的类,内部类的主要作用是将逻辑上相关的类放到一起。n匿名类,没有类名,在定义类的同时就生成该类的一个实例。内部类n内部类是包含在类中的类,内部类也称为“嵌套类”,包含内部类的类又称为“外部类”。n内部类不能与外部类同名。publicclassGroupprivateintage;publicclassStudentStringname;publicStudent(Stringn,inta)name=n;age=a;/调用外部类的成员变量publicvoidoutput()System.out.println(姓名+this.name+年龄+age);publicvoidoutput()Studentstu=newStudent(“刘洋”,24);/创建内部类对象stu.output();/调用内部类的成员方法内部类外部类publicstaticvoidmain(Stringargs)GroupG=newGroup();G.output();class Outerint outer_i=100;void test()Inner in=new Inner();in.display();cla