《JAVA语言与编程第5章继承与多态.ppt》由会员分享,可在线阅读,更多相关《JAVA语言与编程第5章继承与多态.ppt(23页珍藏版)》请在淘文阁 - 分享文档赚钱的网站上搜索。
1、第5章 继承与多态5.1 类的继承类的继承 类的继承也称为类的派生类的继承也称为类的派生,是指一个新类可以继承其他现有类的所有是指一个新类可以继承其他现有类的所有成员成员,包括成员变量和成员方法包括成员变量和成员方法.子类可以根据需要修改继承自父类的属子类可以根据需要修改继承自父类的属性和方法性和方法,还可以添加新的属性和方法还可以添加新的属性和方法.5.1.1 子类定义子类定义1.定义格式定义格式:修饰符修饰符 子类名子类名 extends 父类名父类名 类体类体;例例:public class MyApplet extends JApplet public class MyApplicat
2、ion extends JFrame public class MyApp2.对象替换原则对象替换原则 对象替换意味着子类对象能够用来替代其父类对象对象替换意味着子类对象能够用来替代其父类对象.或者说或者说,父类的句父类的句柄能够指向父类的对象柄能够指向父类的对象,也能够指向子类的对象也能够指向子类的对象.例例:A502.java5.1 类的继承类的继承(续续)3.类继承的基本规则类继承的基本规则:(1)Java中中,Object类是所有类的父类类是所有类的父类(2)每个子类只能有一个直接父类每个子类只能有一个直接父类(3)继承具有传递性继承具有传递性(4)继承不能循环继承不能循环5.1.2
3、super与与this 任何对象任何对象,一旦被创建一旦被创建,就有了两个默认句柄就有了两个默认句柄:关键字关键字super指向父类对指向父类对象象,关键字关键字this指向当前类对象本身指向当前类对象本身.1.在对象创建时使用在对象创建时使用super和和this 对于层次性的继承关系对于层次性的继承关系,子类对象创建时子类对象创建时,系统将自动调用一系列的构系统将自动调用一系列的构造函数造函数.假设假设Object类派生出类派生出G类类,G类派生出类派生出F类类,F类派生出类派生出Me类类.构造构造函函数的调用顺序是固定的数的调用顺序是固定的:总是从总是从Object类开始类开始,沿着继承
4、的顺序沿着继承的顺序,直到直到new所指定的类的构造函数所指定的类的构造函数.(1)如果所有的类都使用默认的构造器如果所有的类都使用默认的构造器,则调用顺序为则调用顺序为:Object()-G()-F()-Me()例例:Me.java5.1 类的继承类的继承(续续)(2)如果父类的构造函数重载了如果父类的构造函数重载了,通过通过super指定调用哪个父类的构造函指定调用哪个父类的构造函数数.在子类的构造函数中在子类的构造函数中,指定希望使用的某个父类的构造函数指定希望使用的某个父类的构造函数,此时此时,该语句必须是子类的构造函数的第一个语句该语句必须是子类的构造函数的第一个语句,否则会产生编译
5、错误否则会产生编译错误.例例:A504.java(3)如果子类自己的构造函数重载了如果子类自己的构造函数重载了,通过通过this在一个构造函数中调用另在一个构造函数中调用另一个构造函数一个构造函数 例例:A505.java 注注:对于对于this()的任何调用的任何调用,如果出现在任何构造函数中如果出现在任何构造函数中,必须是第一个语必须是第一个语句句2.在变量的隐藏时使用在变量的隐藏时使用super和和thisl子类的成员变量隐藏父类的成员变量子类的成员变量隐藏父类的成员变量l类的局部变量隐藏类的成员变量类的局部变量隐藏类的成员变量 例例:A506.java3.在消息传递中使用在消息传递中使
6、用super和和this 例例:A507.java5.1 类的继承类的继承(续续)5.1.3 属性和方法的继承属性和方法的继承1.属性的继承属性的继承l子类虽然可以继承父类的所有属性和方法子类虽然可以继承父类的所有属性和方法,但对于父类的私有属性但对于父类的私有属性,子类只能子类只能通过父类的共有的方法来访问通过父类的共有的方法来访问l从父类继承来的属性从父类继承来的属性,在子类被创建时会另外开辟空间来存储在子类被创建时会另外开辟空间来存储,其值为父类中其值为父类中该属性的初始值该属性的初始值,但之后双方相同的属性就是彼此独立的了但之后双方相同的属性就是彼此独立的了l子类可以覆盖父类的属性子类
7、可以覆盖父类的属性,即子类中定义了一个与父类同名的属性即子类中定义了一个与父类同名的属性,且子类也且子类也继承了父类的这个属性继承了父类的这个属性,那么将有两个同名的属性那么将有两个同名的属性,使用时根据具体情况决定使用时根据具体情况决定使用哪一个使用哪一个:1当使用父类的对象时当使用父类的对象时,调用的就是父类的属性调用的就是父类的属性 2当子类执行继承自父类的操作时当子类执行继承自父类的操作时,处理的将是继承自父类的属性处理的将是继承自父类的属性 3当子类执行自定义的操作时当子类执行自定义的操作时,处理的就是自定义的属性处理的就是自定义的属性 例例:AttibuteInheritanceT
8、est.java2.方法的继承方法的继承 方法的继承与属性类似方法的继承与属性类似,但方法的继承有覆盖和重载两种情况但方法的继承有覆盖和重载两种情况.其中覆盖与属性其中覆盖与属性的覆盖相同的覆盖相同,重载是多态性的体现重载是多态性的体现.例例:TestFunctionOverride.java5.2 类的多态类的多态类的多态性类的多态性:发生在多个类之间发生在多个类之间,是指在子类中重写父类中的某些方法是指在子类中重写父类中的某些方法,在在 程序运行时动态地决定是调用子类的方法还是父类的方法程序运行时动态地决定是调用子类的方法还是父类的方法类的多态类的多态:发生在一个类上发生在一个类上,指在一
9、个类中可以定义多个重名的方法指在一个类中可以定义多个重名的方法,但它但它 们的参数个数和类型不同们的参数个数和类型不同,类的多态体现在方法的重载上类的多态体现在方法的重载上5.2.1 成员函数的重载成员函数的重载 函数的重载是对同名函数的重新定义函数的重载是对同名函数的重新定义,对于这些同名函数对于这些同名函数,系统会通过系统会通过参数个数和类型以及函数的返回值类型加以区分参数个数和类型以及函数的返回值类型加以区分,但不能仅仅通过返回值但不能仅仅通过返回值类型的不同来重载函数类型的不同来重载函数.例例:MethodOverload.java5.2.2 构造函数的重载构造函数的重载 对构造函数进
10、行重载是编写类时常用的方法对构造函数进行重载是编写类时常用的方法,目的是提供多种初始化对目的是提供多种初始化对象的能力象的能力.使得编程人员可以根据实际需要选择合适的构造函数来初始化使得编程人员可以根据实际需要选择合适的构造函数来初始化对象对象5.3 final类和类和final成员成员1.final修饰成员变量修饰成员变量 用用final修饰的成员变量将成为不能被修改的常量修饰的成员变量将成为不能被修改的常量.如果命名常量是一个如果命名常量是一个句柄句柄,仅仅意味着一旦持有某个引用就不得改动仅仅意味着一旦持有某个引用就不得改动,它指向的对象自己的数它指向的对象自己的数据却可以变化据却可以变化
11、.例例:A513.java2.final修饰成员函数修饰成员函数 用用final修饰的成员函数将成为不能被子类重载的最终方法修饰的成员函数将成为不能被子类重载的最终方法.采用采用final方方法的主要目的是提高安全性法的主要目的是提高安全性,使所有人都能够依靠而且必须依靠它来实现使所有人都能够依靠而且必须依靠它来实现特定的功能特定的功能.final方法不应该去调用非方法不应该去调用非final方法方法,final方法所依赖的成方法所依赖的成员员变量应该是变量应该是final或或private变量变量.3.final修饰类修饰类 出于安全性考虑出于安全性考虑,有时需要防止一个类被继承有时需要防止
12、一个类被继承,则可将其声明为则可将其声明为final类类,final类中的所有方法都隐式的自动成为最终方法类中的所有方法都隐式的自动成为最终方法5.4 抽象类和抽象方法抽象类和抽象方法1.抽象类的概念抽象类的概念 抽象类抽象类,就是不能实例化的类就是不能实例化的类,抽象类的属性和方法都是它的子类的公抽象类的属性和方法都是它的子类的公共属性和方法的集合共属性和方法的集合,如果改变抽象类的属性和方法如果改变抽象类的属性和方法,必然会改变所有子必然会改变所有子类的该属性和方法类的该属性和方法.2.抽象类的作用抽象类的作用 提取了所有子类的公共属性和方法提取了所有子类的公共属性和方法,对某些属性或方法
13、仅提供一种形式对某些属性或方法仅提供一种形式化的定义化的定义,这些属性的初始化或方法的实现要在子类中进行这些属性的初始化或方法的实现要在子类中进行.3.抽象方法抽象方法 类中没有具体实现的方法为抽象方法类中没有具体实现的方法为抽象方法,用用abstract修饰修饰,若一个类中含若一个类中含有一个或多个抽象方法有一个或多个抽象方法,该类就是抽象类该类就是抽象类,也用也用abstract修饰修饰,但抽象类中但抽象类中可以没有抽象方法可以没有抽象方法.例例:AbstractDemo.java5.5 接口接口5.5.1 接口的引入接口的引入 编程语言最常用的继承方式是多继承编程语言最常用的继承方式是多
14、继承,然而多继承实现起来非常复杂然而多继承实现起来非常复杂,而单继承虽然实现起来简单而单继承虽然实现起来简单,却不能很好的描述现实世界却不能很好的描述现实世界.因此引入接口的概念来弥补单继承的不足因此引入接口的概念来弥补单继承的不足.接口既拥有多继承的好处接口既拥有多继承的好处,又没有多继承的缺点又没有多继承的缺点多继承的缺点全部来源于实现继承多继承的缺点全部来源于实现继承.5.5.2 创建接口创建接口 接口是定义接口是定义abstract方法和常量的程序单元方法和常量的程序单元,即接口中的方法都是抽象即接口中的方法都是抽象的方法的方法,接口的属性都是常量接口的属性都是常量.接口和类在接口和类
15、在Java语言中是处于同一级别的语言中是处于同一级别的.接口定义格式接口定义格式:public interface 接口名接口名 extends 父接口父接口1,父接口父接口2,public static final 数据类型数据类型 属性名属性名=值值;public abstract native 返回值类型返回值类型 方法名方法名(形参表形参表)throws 异常异常;5.5 接口接口(续续)接口定义的例子接口定义的例子:public interface Constants public static final int ONE=1;public static final int TWO=
16、2;public static final int THREE=3;int getConstants();注注:由于接口的属性是由于接口的属性是public static final修饰的公共常量修饰的公共常量,因此必须在声因此必须在声明时给定初值明时给定初值.5.5.3 实现接口实现接口 一个类要获取某一接口定义的功能一个类要获取某一接口定义的功能,并不是直接继承这个接口中的方法并不是直接继承这个接口中的方法,因为接口中的方法都是没有具体实现的抽象方法因为接口中的方法都是没有具体实现的抽象方法.也就是说也就是说,接口中定义接口中定义的仅仅是实现某一特定功能的一组方法的对外接口和规范的仅仅是实
17、现某一特定功能的一组方法的对外接口和规范,而并没有实现而并没有实现这个功能这个功能,这个功能的实现是在继承这个接口的类中完成的这个功能的实现是在继承这个接口的类中完成的,要由这些类要由这些类来具体定义接口中各抽象方法的方法体来具体定义接口中各抽象方法的方法体.因此因此,在在Java中中,对接口功能的对接口功能的继继承被称为承被称为”实现实现”.5.5 接口接口(续续)实现接口时需要注意的几个问题实现接口时需要注意的几个问题:(1)一个类可以实现多个接口一个类可以实现多个接口,中间用逗号隔开中间用逗号隔开(2)一个接口可以被多个类实现一个接口可以被多个类实现(3)若实现某接口的类不是若实现某接口
18、的类不是abstract修饰的抽象类修饰的抽象类,则在该类中需要实现则在该类中需要实现该接口的全部方法该接口的全部方法(包括接口的父接口中的方法包括接口的父接口中的方法),被实现的方法必须被实现的方法必须和接口中定义的方法具有完全一样的方法名和接口中定义的方法具有完全一样的方法名,返回值和形参表返回值和形参表.否则否则,系统就会认为该类没有完成实现的任务系统就会认为该类没有完成实现的任务.(4)若实现某接口的类是抽象类若实现某接口的类是抽象类,则可以不实现接口中的抽象方法则可以不实现接口中的抽象方法,但在这但在这个抽象类的任何一个非抽象的子类中个抽象类的任何一个非抽象的子类中,都必须为它们的父
19、类所实现的都必须为它们的父类所实现的接口中的所有抽象方法提供具体实现接口中的所有抽象方法提供具体实现.(5)被实现的方法的访问控制符必须显式地使用被实现的方法的访问控制符必须显式地使用public修饰修饰,因为接口的因为接口的方法都是方法都是public修饰的修饰的.例例:student.java5.6 内部类内部类 内部类是定义在某个类的类体或块中的类内部类是定义在某个类的类体或块中的类,内部类中也有内部类中也有成成员变量和成员函数员变量和成员函数.根据内部类定义的位置以及修饰符不同根据内部类定义的位置以及修饰符不同,内部类有很多不同的形式内部类有很多不同的形式,下面介绍几种特殊的情况下面介
20、绍几种特殊的情况.5.6.1 成员类成员类 最直观的一种内部类最直观的一种内部类,就是成员类就是成员类,它与成员变量的地位相它与成员变量的地位相似似.如下例如下例:5.6 内部类内部类(续续)nclass B517n B517()n System.out.println(instance of B.);n n class InnerB/定义内部类定义内部类n InnerB()n System.out.println(Instance of InnerB.);n n /class InnerBnnclass A517/*extends B517*/n public static void mai
21、n(String args)n B517 bbb=new B517();n /A517 bbb=new A517();n B517.InnerB inbbb=bbb.new InnerB();/创建内部类对象创建内部类对象n /A517.InnerB inbbb=bbb.new InnerB();n ();n inbbb=new B517().new InnerB();/一个语句中使用两个一个语句中使用两个newn n5.6 内部类内部类(续续)说明说明:(1)B517定义了一个内部类定义了一个内部类,编译后编译后,硬盘上多了一个硬盘上多了一个B517$InnerB.class(2)内部类的全
22、名是包名内部类的全名是包名.外部类名外部类名.内部类名。声明一个内部类句柄时必内部类名。声明一个内部类句柄时必须用适当的限定名须用适当的限定名.在包外用全名在包外用全名,在外包类在外包类B517外外(比如类比如类A517中中)用用B517.InnerB.(3)内部类的对象必须在外包类的对象预先存在时才能创建内部类的对象必须在外包类的对象预先存在时才能创建,简洁的写法简洁的写法可以在一个语句中使用两个可以在一个语句中使用两个new关键字关键字;(4)内部类的全名不同于其内部类的全名不同于其.class文件名文件名(5)如果如果A517是是B517的子类的子类,它通过继承而拥有了成员类它通过继承而
23、拥有了成员类,但不产生相应但不产生相应的的.class文件文件.5.6 内部类内部类(续续)5.6.2 静态成员类静态成员类 用修饰符用修饰符static修饰的成员类称为静态成员类修饰的成员类称为静态成员类.静态成员类与静态成员静态成员类与静态成员变量相似变量相似,只与外部类相关而不依赖外部类的实例只与外部类相关而不依赖外部类的实例,因此创建一个静态成因此创建一个静态成员员类的对象并不需要一个外包类对象的存在类的对象并不需要一个外包类对象的存在.n例例:class B521n protected static class InnerB /静态成员类静态成员类nnclass A521n publ
24、ic static void main(String args)n /(new B521();n B521.InnerB inB=new B521.InnerB();n (inB);n /(new B521.InnerB();n n5.6 内部类内部类(续续)注注:(1)静态成员类的名字要使用全名静态成员类的名字要使用全名,如作为数据类型时是如作为数据类型时是B521.InnerB,作为构造器时是作为构造器时是B521.InnerB().(2)静态成员类和非内部类非常相似静态成员类和非内部类非常相似,可以被可以被public,private,final或或abstract修饰修饰,且可以继承任
25、何类和接口且可以继承任何类和接口(3)静态成员类可以被任何有访问权限的其他类继承静态成员类可以被任何有访问权限的其他类继承,然而继然而继承者没有了静态成员类与其外部类的密切关系承者没有了静态成员类与其外部类的密切关系5.6 内部类内部类(续续)5.6.3 局部类局部类 在方法体中甚至在其中的代码块中定义的类叫做局部类在方法体中甚至在其中的代码块中定义的类叫做局部类,局部类与局部局部类与局部变量相似变量相似,它是它的外包方法私有的它是它的外包方法私有的,不能有修饰符不能有修饰符,外界不能访问外界不能访问.但局但局部部类和局部变量唯一不同的地方就是类和局部变量唯一不同的地方就是:局部类的对象在局部
26、类的对象在heap中分配内存中分配内存.局部类在使用时的特点局部类在使用时的特点:1.局部类只能访问外包方法的局部类只能访问外包方法的final局部变量局部变量 位于方法内部的局部类位于方法内部的局部类,可以访问外包方法之外的类的一切成员可以访问外包方法之外的类的一切成员,因为因为外部类完全信任所有内部类外部类完全信任所有内部类.局部类可以访问外包方法的局部变量和参数局部类可以访问外包方法的局部变量和参数,但在访问时遇到一个问题但在访问时遇到一个问题,生命周期不同生命周期不同,延长局部变量声明周期的方法是将它变成常量延长局部变量声明周期的方法是将它变成常量,因此局部因此局部变量只能访问外包方法
27、的变量只能访问外包方法的final局部变量局部变量.如下例如下例:5.6 内部类内部类(续续)nclass B523n private int k=10;n public void go(int x,final int y)n int a=x+y;n final int b=xy;n class InBn public void foo()n (y);n /试试试试k,x,a,bn n InB here=new InB();n here.foo();n nnpublic class A523n public static void main(String args)n new B523().g
28、o(1,2);n n5.6 内部类内部类(续续)(2)局部类由父类句柄持有局部类由父类句柄持有 局部类本身在外包方法外面是无法使用的局部类本身在外包方法外面是无法使用的,一般而言一般而言,外包方法调用结外包方法调用结束束,则局部类的对象常常因为句柄的失效而成为垃圾则局部类的对象常常因为句柄的失效而成为垃圾.但局部类可以是某但局部类可以是某个类的子类个类的子类,当希望局部类的对象能够继续存在时当希望局部类的对象能够继续存在时,就可以由父类句柄持就可以由父类句柄持有局部类的引用有局部类的引用.如下例如下例:nclass C524/局部类的父类局部类的父类n void foo()nnclass B5
29、24n C524 go(int x,final int y)n class InGo extends C524n void foo()n (y);n /override!n /class InGon InGo here=new InGo();n here.foo();n return here;n void gogo(C524 c00)n c00.foo();n nnpublic class A524n public static void main(String args)n C524 cccc=new B524().go(1,2);n cccc.foo();n C524 cc=new B5
30、24().go(1,20);n new B524().gogo(cc);n n5.6 内部类内部类(续续)5.6.4 匿名类匿名类nabstract class C525/局部类的父类局部类的父类n abstract void foo();nnclass B525n public C525 go(int x,final int y)n return new C525()/返回什么?返回什么?n public void foo()n (y);n n ;/是一个语句,要以是一个语句,要以;结束结束n n public void gogo(C525 c00)n c00.foo();n n5.6 内部
31、类内部类(续续)npublic class A525n public static void main(String args)n C525 cccc=new B525().go(1,2);n cccc.foo();n C525 cc=new B525().go(1,20);n new B525().gogo(cc);n new B525().gogo(new C525()/*/n public void foo()n (Hello);n n );n n5.6 内部类内部类(续续)1.匿名类的特点匿名类的特点:(1)匿名类没有类名匿名类没有类名,它必须继承一个类或实现一个接口它必须继承一个类或实现一个接口,且不能有显式的且不能有显式的extends或或implements子句子句(2)匿名类不能有构造函数匿名类不能有构造函数,因为它没有类名因为它没有类名(3)匿名类只能一次性地创建其对象匿名类只能一次性地创建其对象,并由父类句柄持有并由父类句柄持有(4)匿名类不需要初始化匿名类不需要初始化,它只有默认构造器它只有默认构造器,而通常情况下而通常情况下,匿名类很少匿名类很少需要初始化需要初始化(5)匿名类既可以在方法体中匿名类既可以在方法体中,又可以在参数列表中又可以在参数列表中.
限制150内