1、继承的概念和作用子类的声明类成员修饰符与继承的关系理解父类和子类的关系,在子类中使用父类成员(方法)继承机制下,对象创建的过程(构造方法的使用,super调用)子类对父类方法的重写(super调用)代码复用的手段 “is-a”关系:类之间是继承的关系“has-a”关系:类之间是组合的关系继承:从已有的类中派生出新的类。新的类能吸收已有类的数据属性和行为 并能扩展新的能力 举例:商品Product-productName:String-desciption:String-addTime:Date-salePrice:double-keywords:String+()Book-author:Str
2、ing-publisher:String-publishTime:Date-wordsNumber:String-edition:String-isbn:String+()Clothes-color:String-size:String+()父类是子类的一般化,子类是父类的特例化(具体化)。父类也称为超类或基类。父 类子 类学生研究生、大学生、小学生形状三角形、圆、矩形雇员教师、医生、职员交通工具轿车、卡车、公交车水果苹果、梨、桃、桔超类/基类父类子类parents/super/basechild/derived继承分类 单继承:一个子类最多只能有一个父类。多继承:一个子类可有两个以上的父类。
3、Java类只支持单继承,而接口支持多继承。Java多继承的功能则是通过接口方式来间接实现的。子类定义的一般格式 类修饰符 class 子类名 extends 父类名 成员变量定义;成员方法定义;在子类的定义中,用关键字extends来明确指出它所继承的父类。【例5-1】通过继承Person类派生DeliveryMan类。快递公司的不同职工职工Person快递员 DeliveryMan 数据成员配送区域deliveryArea 获取配送区域方法getDeliveryArea()获取快递员信息方法getInfo()判断某区域是否在配送范围内方法isArrived()Person-id:String
4、-name:String-birthday:Date-+Person()+setId(id:String):void+getId():String+setName(name:String):void+getName():String+setBirthday(birthday:Date):void+getBirthday():DateDeliveryMan-deliveryArea:String+DeliveryMan()+DeliveryMan(deliveryArea:String)+setDeliveryArea(deliveryArea:String)+getInfo():String+
5、isArrived(area:String):boolean要区分“存在”与“可见”之间的关系。private的成员与其他成员一样都被继承到子类中(是存在的),只是它们不能被子类直接使用而已(不可见)。成员访问控制修饰符在继承中的性质 public、private、package、protected 父类的public成员可以在父类中使用,也可以在子类使用。程序可以在任何地方访问public父类成员。父类的private成员仅在父类中使用,在子类中不能被访问。父类的protected成员可在子类被访问,无论子类与父类是否存储在同一个包下。父类的package成员可在同一包的子类中被访问。子类从
6、父类继承成员时,父类的所有public、protected、package成员,在子类中都保持它们原有的访问修饰符。例如,父类的public成员成为子类的public成员。父类的protected成员也会成为子类的protected成员。子类只能通过父类所提供的非private方法来访问父类的private成员。类类A A成员的成员的访问控制符访问控制符类类A A对类对类A A成员成员的访问权限的访问权限第三方类对类第三方类对类A A成员成员的访问权限的访问权限子类子类B B对类对类A A成员成员的访问权限的访问权限与A同包与A不同包与A同包与A不同包publicpublicprotected
7、protected默认默认(package)(package)privateprivate【例5-2】分析同包下无继承关系的类之间成员的访问控制权限。packagepackage chap5.example.access;publicpublic classclass C publicpublic intint a=1;protectedprotected intint b=2;intint c=3;privateprivate intint d=4;publicpublic intint getD()returnreturn d;packagepackage chap5.example.ac
8、cess;publicpublic classclass AccessDemo publicpublic staticstatic voidvoid main(String args)C coo=newnew C();System.out.println(coo.a);System.out.println(coo.b);System.out.println(coo.c);/System.out.println(coo.d);System.out.println(coo.getD();【例5-3】分析不同包下子类对父类成员的访问控制权限。packagepackage chap5.example.
9、access.sub;publicpublic classclass C publicpublic intint a;protectedprotected intint b;intint c;privateprivate intint d;publicpublic intint getD()returnreturn d;packagepackage chap5.example.access;importimport chap5.example.access.sub.C;publicpublic classclass AccessDemo extendsextends C publicpubli
10、c voidvoid getInfo()System.out.println(a);System.out.println(b);System.out.printlnSystem.out.println(c);(c);System.out.printlnSystem.out.println(d);(d);Object类:Java中所有类的父类,定义和实现了Java系统下所有类的共同行为,所有的类都是由这个类继承、扩充而来的。认识Object类中的方法【例5-4】定义Animal类的子类Bird,并重写它的move()方法。public classpublic class Animal publi
11、c voidpublic void move()System.out.println(我可以move.);public classpublic class Bird extendsextends Animalpublic voidpublic void move()System.out.println(我可以在天空飞翔.);public staticvoidpublic staticvoid main(String args)Bird bird=newnewBird();bird.move();/输出我可以在天空飞翔.方法的重写遵循“两同两小一大”的规则“两同”:方法名称相同、形参列表相同“两
12、小”子类方法返回值类型父类方法返回值类型 子类方法抛出的异常父类方法抛出的异常“一大”:子类方法的访问权限父类方法的访问权限 重写方法时不能改变方法的static或非static性质。Object类中定义了9个方法 clone()finalize()toString()equals()hashCode()notify()notifyAll()wait()getClass()【例5-5】在DeliveryMan类中重写toString方法。public class public class DeliveryMan extendsextends Person privateprivate Stri
13、ng deliveryArea;publicpublic String toString()String str=getId()+,+getName()+n配送范围:;intint i;forfor(i=0;ideliveryArea.length-1;i+)/除最后一个外,都有一个逗号str+=deliveryAreai+,;return return str+deliveryAreai;【例5-5】在DeliveryMan类中重写toString方法。public classpublic class Test public static voidpublic static void mai
14、n(String args)DeliveryMan dm=new new DeliveryMan();dm.setId(007);dm.setName(Bang);dm.setDeliveryArea(newnew String南锣鼓巷,烟袋斜街,雨儿胡同,帽儿胡同,黑芝麻胡同);System.out.println(快递员信息:+dm);【例5-6】利用super调用父类的同名方法。public classpublic class Animal public voidpublic void move()System.out.println(我可以move.);public classpubl
15、ic class Bird extendsextends Animalpublic voidpublic void move()super.move();super.move();/调用父类的move()方法System.out.println(我可以在天空飞翔.);public static voidpublic static void main(String args)Bird bird=new new Bird();bird.move();/输出我可以move我可以在天空飞翔.【例5-7】在Student类中重写Object的clone()方法,实现Student对象的深复制。Objec
16、t类中的clone()方法的访问修饰符是protected,所以不能用下面的方式复制对象。publicpublic classclass Student privateprivate String name;privateprivate intint age;publicpublic Student()publicpublic Student(String name,intint age)thisthis.name=name;thisthis.age=age;publicpublic classclass Test publicpublic staticstatic voidvoid main
17、(String args)Student stu1=newnew Student(Lucy,15);Student stu2=nullnull;trytry/此句报错stu2=(Student)stu1.clone();catchcatch(CloneNotSupportedException e)e.printStackTrace();Test类相对于Student类来讲,身份是“第三方类”(既不是Student类本身,也不是Student的子类)clone()方法来自于Object,与Test不同包,所以Test没有权利访问Student从Object继承来的protected修饰的方法。
18、publicpublic classclass Student implementsimplements Cloneable /implements Cloneable表示实现Cloneable接口privateprivate String name;privateprivate intint age;publicpublic Object clone()/重写Object类的clone()方法Student stu=nullnull;trytry stu=(Student)supersuper.clone();/调用Object类的clone()功能完成复制 catchcatch(Clone
19、NotSupportedException e)e.printStackTrace();returnreturn stu;publicpublic classclass Test publicpublic staticstatic voidvoid main(String args)Student stu1=newnew Student(Lucy,15);Student stu2=(Student)stu1.clone();System.out.println(stu1);System.out.println(stu2);浅复制001zhang堆内存teacher1001zhang堆内存tea
20、cher1001zhang深复制001zhang堆内存teacher1001zhang堆内存teacher1001zhangteacher1【例】向Student中组合一个Teacher类的引用成员。实现深复制时,如果对象中包含引用成员,则该引用成员所属类也需要重写clone()方法。在复制对象时,再单独复制引用成员所指对象。请思考下面代码的运行结果是什么?请思考下面代码的运行结果是什么?publicpublic classclass Test publicpublic staticstatic voidvoid main(String args)Teacher teacher=newnew
21、Teacher(Grace);Student stu1=newnew Student(Lucy,15,teacher);Student stu2=(Student)stu1.clone();stu1.getTeacher().setName(Kenzo);stu1.getTeacher().setName(Kenzo);System.System.outout.println(stu1:+stu1);.println(stu1:+stu1);System.System.outout.println(stu2:+stu2);.println(stu2:+stu2);代码改进如下:publicpu
22、blic classclass Teacher implementsimplements Cloneablepublicpublic Object clone()/重写clone方法Teacher tea=nullnull;trytry tea=(Teacher)supersuper.clone();catchcatch(CloneNotSupportedException e)e.printStackTrace();returnreturn tea;publicpublic classclass Student implementsimplements Cloneablepublicpubl
23、ic Object clone()Student stu=nullnull;trytry stu=(Student)supersuper.clone();catchcatch(CloneNotSupportedException e)e.printStackTrace();/复制引用成员所指对象this.teacherthis.teacher=(Teacher)=(Teacher)stu.getTeacherstu.getTeacher().clone();().clone();returnreturn stu;继承下的构造方法的调用次序继承下的构造方法的调用次序 子类构造方法在执行自己的任务
24、之前,将显式显式地(通过super引用)或隐式隐式地(调用父类默认的无参数构造方法)调用其直接父类的构造方法。类似地,如果父类派生于另一个类,则要求父类的构造方法调用上一级类的构造方法,依此类推。调用请求中,最先调用的一定是Object类的构造方法。创建对象的过程:先父后子。【例5-8】已知圆Circle椭圆Ellipse形状Shape的继承关系,查看Circle对象构建的过程。java.lang.ObjectEllipse-a:double-b:double+Ellipse()+Ellipse(name:String)+Ellipse(name:String,a:double,b:doubl
25、e)+getArea():doubleShape-name:String+Shape()+Shape(name:String)Circle+Circle()+Circle(name:String,r:double)+getArea():doublepublic classpublic class Shape privateprivate String name;publicpublic Shape()System.out.println(Shape().);public classpublic class Ellipse extendsextends Shapeprivate double p
26、rivate double a;/短轴private double private double b;/长轴publicpublic Ellipse()System.out.println(Ellipse().);public classpublic class Circle extendsextends Ellipsepublicpublic Circle()System.out.println(Cicle().);为了避免错误,父类中至少定义一个为了避免错误,父类中至少定义一个无参的构造方法。无参的构造方法。子类不会继承父类的构造方法,但是子类可以调用父类的构造方法,如同一个类的构造方法可
27、以用this()调用自己的重载构造方法一样。子类调用父类构造方法使用super()完成。构造方法调用的过程(1)子类构造方法的第一行使用super()显式调用父类的构造方法,编译系统根据super的实参列表调用对应的父类构造方法。(2)子类构造方法的第一行使用this()显式调用本类重载的构造方法,编译系统根据this的实参列表调用对应的本类构造方法。执行本类另一个构造方法时会显式或隐式地调用父类的构造方法。(3)如果子类构造方法中既没有super调用,也没有this调用,系统会在执行子类构造方法前隐式调用父类无参的构造方法。5.4.1 final5.4.1 final修饰符修饰符 final
28、修饰类时,类不能被继承 final修饰方法时,方法不能被重写 final修饰变量时,变量只能被赋值一次1 1finalfinal类类 final修饰的类不能有子类。像java.lang.String、java.lang.Math等就是final类,不能被继承,它们的方法禁止被重写。2final方法 final修饰的方法不能被重写,例如java.lang.Object类中的getClass()方法。Object类是一定会被继承的(它是所有类直接或间接的父类),但是Java不希望子类重写这个方法,所以使用final把它保护起来。3 3finalfinal变量变量无论final修饰哪种变量,无论这种
29、变量在何处被赋初值,final变量的赋值永远只能有一次。final成员变量 final局部变量 final方法参数 publicpublic protectedprotected默认默认privateprivatestaticstaticfinalfinal类类数据成员数据成员方法成员方法成员局部变量局部变量继承允许根据其他类的实现来定义一个新类,这种生成子类的复用通常被称为白箱复用(Whitebox reuse)。“白箱”是相对可视性而言,在继承方式中父类的内部细节对子类可见,所以称为白箱。组合是类继承之外的另一种复用选择,新的更复杂的功能通过组合对象来获得,这种复用被称为黑箱复用(Blackbox reuse),被组合的对象的内部细节是不可见的,对象只以“黑箱”的形式出现(被组合的对象必须定义了良好的数据访问接口)。