第五讲面向对象程序设计思想(3)——继承引子在评测成绩程序里,我们已经知道考试课类和考查课类都继承了课程类。“继承”的定义是:特殊类的对象拥有其一般类的全部属性与服务。在JAVA中,特殊类称作“子类”或“派生类”,一般类称作“超类”、“基类”或者“父类”。例如鸽子是鸟的子类,因此所有“鸟”该有的特性,鸽子也都有。5.1继承如果树上停着一只鸽子、两只麻雀、三只乌鸦,我们问树上有几只鸟,大家会毫不犹豫地说六只。因为鸽子、麻雀、乌鸦都是鸟的子类,因此我们可以用“鸟”这个超类来统称它们,也就是超类的引用可以指向子类的对象。但反过来就不成立了,子类的引用不能指向超类的对象,毕竟鸟不是鸽子。由此,我们可以得到下面的结论:1、子类对象可以被视作是其超类的一个对象;2、超类对象不能被视作是其子类的一个对象;3、超类的引用可以指向其子类的对象;4、子类的引用不可以指向其超类的对象。再进一步的考虑,如果上面的六只鸟都叫了起来,“叽叽”“咕咕”却并不相同。例如下面代码:鸟a=new鸽子();鸟b=new麻雀();鸟c=new乌鸦();a.叫();b.叫();c.叫();虽然都是叫,但各有不同。因为a、b、c所表示的对象分别是鸽子、麻雀和乌鸦它们虽同属于鸟类,但各自有各自的实现。5.1.1继承的UML表示继承是面向对象语言中特有的复用工具。子类通过继承可以获得超类的所有功能,然后更具自生的特点加以扩展和改造,就能以简单的程序代码来实现功能强大功能了。《荀子·劝学篇》中所说的“青出于蓝而胜于蓝”正好为我们解释了继承的意义。在UML中,类的继承关系也称为泛化关系。泛化和继承表示的是同一种关系,只是方向不同。我们说“子类继承超类”或者说“超类泛化为子类”。在UML的类图中使用空心三角的箭头()表示继承,箭头指向超类。例如上文中鸟、鸽子、麻雀和乌鸦的类图如下:5.1.2JAVA中实现继承JAVA中要实现继承,只要在子类的申明中使用“extends”关键字来注明其超类就可以了。例如:class鸟{void叫(){}}class鸽子extends鸟{void叫(){}}5.1.3子类调用父类的构造方法父类的构造方法不能被子类继承。子类不能直接通过方法名调用父类的构造方法,而通过super调用,且位于子类构造方法的首行。当子类的某个构造方法没有调用父类的一个构造方法,通过这个构造方法创建对象时,会自动调用父类的缺省构造方法。例5.1classGrandPa{//fromprotectedGrandPa(){System.out.println(defaultGrandPa);}//topublicGrandPa(Stringname){System.out.println(name);}}classFatherextendsGrandPa{protectedFather(){System.out.println(defaultFather);}publicFather(StringgrandPaName,StringfatherName){super(grandPaName);System.out.println(fatherName);}}publicclassSonextendsFather{publicSon(){System.out.println(defaultSon);}publicSon(StringgrandPaName,StringfatherName,StringsonName){super(grandPaName,fatherName);//hereSystem.out.println(sonName);}publicstaticvoidmain(String[]args){Sons1=newSon();Sons2=newSon(A,B,C);}}输出结果defaultGrandPadefaultFatherdefaultSonABC如果将from到to删除,则编译出错如果将here行删除,则输出:defaultGrandPadefaultFatherdefaultSondefaultGrandPadefaultFatherC例5.2classClassA{publicintvarA=1;protectedvoidmethodA(){}}classClassBextendsClassA{protectedintvarB=1;publicvoidmethodB(){}}classClassCextendsClassB{voidmethodC(){varA=2;varB=2;methodA();methodB();}publicstaticvoidmain(String[]args){ClassCc=newClassC();c.varA=3;c.varB=3;c.methodA();c.methodB();}}5.2继承中的初始化过程在初始化子类之间完成父类的初始化:(1)顶级父类的类属性(static)初始化(2)下一级父类的类属性(static)初始化(3)……(4)本类的类属性(static)初始化(5)顶级父类的实例属性初始化(6)顶级父类的构造方法(7)下一级父类的实例属性初始化(8)下一级父类的构造方法(9)……(10)……(11)本类的实例属性初始化(12)本类的构造方法例5.3classNode{publicNode(inti){System.out.println(Node(+i+));}}classBase{publicstaticNoden1=newNode(1);publicNoden2=newNode(2);publicBase(inti){System.out.println(Base(+i+));}}classSonextendsBase{publicstaticNoden3=newNode(3);publicstaticNoden4;publicNoden5=newNode(5);publicNoden6;publicSon(inti){super(i);n4=newNode(4);n6=newNode(6);System.out.println(Son(+i+));}}classPogram{publicstaticvoidmain(String[]args){newSon(1);newSon(2);}publicstaticNoden1=newNode(1);publicstaticBaseb1=newBase(1);}输出:Node(1)Node(1)Node(2)Base(1)Node(3)Node(2)Base(1)Node(5)Node(4)Node(6)Son(1)Node(2)Base(2)Node(5)Node(4)Node(6)Son(2)5.3final类如果将一个类声明为final,表示这个类不能被继承finalclassBase{……}classSonextendsBase//error!{……}5.4Object类JAVA中所有类的顶级父类是Object类。。这意味着一个Object类型的引用变量可以引用其他任何一个类的对象。Object定义了下面的方法,意味着它们可以被用于任何对象:注意两个方法:equals()和toString()。equals()方法比较两个对象的内容。如果对象是相等的,它返回true,否则返回false。toString()方法返回一个包含调用它的对象描述的字符串。而且,该方法在对象用println()输出时自动调用。我们可以重写该方法来便于输出。例5.4classNode{publicStringtoString(){returnNode;}}classProgram{publicstaticvoidmain(String[]args){System.out.println(newNode());}}输出:Node5.5方法覆盖如果基类的方法不符合子类的运算,那么子类就要将基类的方法覆盖。1、子类的方法名称以及参数表必须与父类中的方法名称、参数表相同2、覆盖方法的返回类型必须与父类中的方法相同3、父类的静态方法不能子类方法覆盖,但能被子类的静态方法隐藏4、final方法不能被覆盖1、如果p是父类Parent的对象,而c是子类Child的对象,则语句c=p是正确的。()2、类Parent、Child定义如下:1.classParent2.{publicfloataFun(floata,floatb)throws3.IOException{}4.}5.classChildextendsParent{6.7.}将以下哪种方法插入行6是不合法的。()A、floataFun(floata,floatb){}B、publicintaFun(inta,intb)throwsException{}C、publicfloataFun(floatp,floatq){}D、publicintaFun(inta,intb)throwsIOException{}3、写出以下程序的运行结果。classFirst{First(){System.out.println(inFirst);}}publicclassSecondextendsFirst{Second(){System.out.println(inSecond);}publicstaticvoidmain(String[]args){Secondmine=newSecond();}}FAinFirstinSecond薃肀莂蒃袂肀肂虿袈聿芄薂螄肈莇螇蚀肇葿薀罿肆腿莃袅肅芁薈螁膄莃莁蚇膄肃薇薃膃芅荿羁膂莈蚅袇膁蒀蒈螃膀膀蚃虿腿节蒆羈芈莄蚁袄芈蒆蒄螀芇膆蚀蚆袃莈蒃蚂袂蒁螈羀袁膀薁袆袁芃螆螂袀莅蕿蚈衿蒇莂羇羈膇薇袃羇艿莀蝿羆蒂薆螅羅膁蒈蚁羅芄蚄罿羄莆蒇袅羃蒈蚂螁羂膈蒅蚇肁芀蚁薃肀莂蒃袂肀肂虿袈聿芄薂螄肈莇螇蚀肇葿薀罿肆腿莃袅肅芁薈螁膄莃莁蚇膄肃薇薃膃芅荿羁膂莈蚅袇膁蒀蒈螃膀膀蚃虿腿节蒆羈芈莄蚁袄芈蒆蒄螀芇膆蚀蚆袃莈蒃蚂袂蒁螈羀袁膀薁袆袁芃螆螂袀莅蕿蚈衿蒇莂羇羈膇薇袃羇艿莀蝿羆蒂薆螅羅膁蒈蚁羅芄蚄罿羄莆蒇袅羃蒈蚂螁羂膈蒅蚇肁芀蚁薃肀莂蒃袂肀肂虿袈聿芄薂螄肈莇螇蚀肇葿薀罿肆腿莃袅肅芁薈螁膄莃莁蚇膄肃薇薃膃芅荿螀羀膆蒃蚆肀芈芆薂聿羈蒂蒈肈肀芅袆肇芃薀螂肆莅莃蚈肅肅薈薄蚂膇莁蒀蚁艿薇蝿螀罿荿蚅蝿肁薅薁螈膄莈薇螈莆膀袆螇肆蒆螁螆膈艿蚇螅芀蒄薃螄羀芇葿袃肂蒃螈袂膄芅蚄袂芇蒁蚀袁肆芄薆袀腿蕿蒂衿芁莂螁袈羁薇蚇袇肃莀薃羆膅薆葿羆芈荿螇羅羇膁螃羄膀莇虿羃节芀薅羂羂蒅蒁羁肄芈螀羀膆蒃蚆肀芈芆薂聿羈蒂蒈肈肀芅袆肇芃薀螂肆莅莃蚈肅肅薈薄蚂膇莁蒀蚁艿薇蝿螀罿荿蚅蝿肁薅薁螈膄莈薇螈莆膀袆螇肆蒆螁螆膈艿蚇螅芀蒄薃螄羀芇葿袃肂蒃螈袂膄芅蚄袂芇蒁蚀袁肆芄薆袀腿蕿蒂衿芁莂螁袈羁薇蚇袇肃莀薃羆膅薆葿羆芈荿螇羅羇膁螃羄膀莇虿羃节芀薅羂羂蒅蒁羁肄芈螀羀膆蒃蚆肀芈芆薂聿羈蒂蒈肈肀芅袆肇芃薀螂肆莅莃蚈肅肅薈薄蚂膇莁蒀蚁艿薇蝿螀罿荿蚅蝿肁薅薁螈膄莈薇螈莆膀袆螇肆蒆螁螆膈艿蚇螅芀蒄薃螄羀芇葿袃肂蒃螈袂膄芅蚄袂芇蒁蚀袁肆芄薆袀腿蕿蒂衿芁莂螁袈羁薇蚇袇肃莀薃羆膅薆葿羆芈荿螇羅羇膁螃羄膀莇虿羃节芀薅羂羂蒅蒁羁肄芈螀羀膆蒃蚆肀芈芆薂聿羈蒂蒈肈肀芅袆肇芃薀螂肆莅莃蚈肅肅薈薄蚂膇莁蒀蚁艿薇蝿螀罿荿蚅蝿肁薅薁螈膄莈薇螈莆膀袆螇肆蒆螁螆膈艿蚇螅芀蒄薃螄羀芇葿袃肂蒃螈袂膄芅蚄袂芇蒁蚀袁肆芄薆袀腿蕿蒂衿芁莂螁袈羁薇蚇袇肃莀薃羆膅薆葿羆芈荿螇羅羇膁螃羄膀莇虿羃节芀薅羂羂蒅蒁羁肄芈螀羀膆蒃蚆肀芈芆薂聿羈蒂蒈肈肀芅袆肇芃薀螂肆莅莃蚈肅肅薈薄蚂膇莁蒀蚁艿薇蝿螀罿荿蚅蝿肁薅薁螈膄莈薇螈莆膀袆螇肆蒆螁螆膈艿蚇螅芀蒄薃螄羀芇葿袃肂蒃螈袂膄芅蚄袂芇蒁蚀袁肆芄薆袀腿蕿蒂衿芁莂螁袈羁薇蚇袇肃莀薃羆膅薆葿羆芈荿螇羅羇膁螃羄膀莇虿羃节芀薅羂羂蒅蒁羁肄芈螀羀膆蒃蚆肀芈芆薂聿羈蒂蒈肈肀芅袆肇芃薀螂肆莅莃蚈肅肅薈薄蚂膇莁蒀蚁艿薇蝿螀罿荿蚅蝿肁薅薁螈膄莈薇螈莆膀袆螇肆蒆螁螆膈艿蚇螅芀蒄薃螄羀芇葿袃肂蒃螈袂膄芅蚄袂芇蒁蚀袁