1、第第5 5章章 继承、接口和泛型继承、接口和泛型 本章导读本章导读n子类与父类n子类的继承性n子类对象的构造过程n成员变量隐藏和方法的重写nfinal类与final方法n对象的上转型对象 本章导读本章导读n继承和多态nabstract类n面向抽象编程n接口和接口回调n面向接口编程n内部类、匿名类、异常类和泛型类15.1 5.1 子类与父类子类与父类 继承是一种由已有的类创建新类的机制。利用继承,我们可以先创建一个共有属性的一般类,根据该一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。由继承而得到的类称为子类,被继承的类称为父类(超类)。父类可以
2、是自己编写的类也可以是java类库中的类。利用继承有利于实现代码的重复使用,子类只需要添加新的功能代码即可。Java不支持多重继承,即子类只能有一个父类。class 子类名子类名 extends 父类名父类名 .如果一个类的声明中没有使用关键字extends,这个类被系统默认为是Object的子类,Object是包java.lang中的类。也就是说,类声明class A 与class A extends Object 是等同的。25.2 5.2 子类的继承性子类的继承性 1 1继承的定义继承的定义 子类的成员中有一部分是子类自己声明定义的,另一部分是从它的父类继承的。子类继承父类的成员变量作为
3、自己的一个成员变量,就好像它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法操作。子类继承父类的方法作为子类中的一个方法,就像它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法调用。32.2.子类和父类在同一包中的继承性子类和父类在同一包中的继承性 如果子类和父类在同一个包中,那么子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法。继承的成员变量以及方法的访问权限保持不变。下面的例5-1中(效果如图5.1所示),Son是Father的子类,而GrandSon是Son的子类,请注意子类的继
4、承性。43 3子类和父类不在同一包中的继承性子类和父类不在同一包中的继承性 如果子类和父类不在同一个包中,那么子类只能继承父类的protected、public成员变量和方法,继承的成员或方法的访问权限不变。如果子类和父类不在同一个包里,子类不能继承父类的友好变量和友好方法。55.3 5.3 子类对象的构造过程子类对象的构造过程 当用子类的构造方法创建一个子类的对象时,子类的构造方法总是先调用父类的某个构造方法,如果子类的构造方法没有指明使用父类的哪个构造方法,子类就调用父类的不带参数的构造方法。因此,我们可以这样来理解子类创建的对象:将子类中声明的成员变量作为子类对象的成员变量。父类的成员变
5、量也都分配了内存空间,但只将其中一部分(继承的那部分)作为子类对象的成员变量。子类对象内存示意如图5.2所示。例5-2中(效果如图5.3所示),子类调用继承的方法操作这些未被子类继承却分配了内存空间的变量。6子类对象内存示意如图子类对象内存示意如图5.2 75.4 5.4 成员变量的隐藏和方法的重写成员变量的隐藏和方法的重写 1成员变量的隐藏 子类可以隐藏继承的成员变量,当在子类中定义和父类中同名的成员变量时,子类就隐藏了继承的成员变量,即子类对象以及子类自己声明定义的方法操作与父类同名的成员变量。例5-3中(效果如图5.4所示),在这个例子中子类隐藏了从父类继承的double型变量。特别需要
6、注意的是,尽管子类可以隐藏从父类继承来的成员变量,但是子类仍然可以使用从父类继承的方法操作被隐藏的成员变量,比如,上述例子中,子类对象通过使用从父类继承的方法 f 操作被隐藏的double型成员变量 y。82方法重写 子类也可以隐藏方法,子类通过方法重写来隐藏继承的方法。方法重写是指:子类中定义一个方法,并且这个方法的名字、返回类型、参数个数和类型与从父类继承的方法完全相同。子类通过方法的重写可以把父类的状态和行为改变为自身的状态和行为。这时,如果子类想使用被隐藏的方法,必须使用关键字super,我们将在后面讲述super的用法。下面这个例子5-4可以帮助我们更好的理解方法的重写。效果如图5.
7、5 需要注意的是:需要注意的是:方法重写时一定要保证方法的名字、类型、参数个数和类型同父类的某个方法完全相同,只有这样,子类继承的这个方法才被隐藏。如果子类在准备隐藏继承的方法时,参数个数或参数类型与父类的方法不尽相同,那实际上也没有隐藏继承的方法,这时子类就出现两个方法具有相同的名字。但保证了参数的不同,也就是说子类出现了重载的方法重载的方法,即有两个方法的名字相同,但参数不同。在下面的例例子子5-5中(效果如图5.6所示),子类并没有隐藏父类的方法f()。9例子5-4,例子5-5 效果图103访问修饰符protected的进一步说明 现在要对protected总结得更全面些。如果用类D在D
8、本身中创建了一个对象,那么该对象总是可以通过运算符“.”访问继承的或自己定义的protected变量和protected方法。如果在另外一个类中,如类Other,用类D创建了一个对象object,该对象通过“.”运算符访问protected变量和protected方法的权限如下所述 子类D的protected成员变量和方法,如果不是从父类继承来的,object访问这些protected成员变量和方法时,只要类Other和类D在同一个包中就可以了。如果子类D的对象的protected成员变量或protected方法是从父类继承的,那么就要一直追溯到该protected成员变量或方法的“祖先”类,
9、即类A。如果类Other和类A在同一个包中,object对象能访问继承的protected变量和protected方法。115.5 Super 5.5 Super 关键字关键字 Super关键字有两种用法:一种用法是子类使用super调用父类的构造方法,另一种用法是子类使用super调用被子类隐藏的成员变量和方法。1 1使用使用supersuper调用父类的构造方法调用父类的构造方法 子类不继承父类的构造方法,因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用并且必须使用关键字supersuper来表示,而且supersuper必须是子类构造方法中的第一条语句。例子5-6中,子类的
10、构造方法中使用super调用父类的构造方法。效果 如图5.7.2 2使用使用supersuper操作被隐藏的成员变量和方法操作被隐藏的成员变量和方法 当子类中定义了一个方法,并且这个方法的名字、返回类型、参数个数和类型和父类的某个方法完全相同时,子类从父类继承的这个方法将被隐藏。如果我们在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字关键字supersuper。例子5-7中,子类使用super调用被隐藏的成员变量和方法。效果 如图5.812例子5-6,例子5-7 效果图135.6 final 5.6 final 类和类和finalfinal方法方法 final类不能被继承,即不能有子类
11、,如 final class Afinal class A A就是一个final类。有时候出于安全性的考虑,将一些类修饰为final类。例如,Java提供的String类,它对于编译器和解释器的正常运行有很重要的作用,对它不能轻易改变,因此它被修饰为final类。如果一个方法被修饰为final方法,则这个方法不能被重写,即不允许子类重写隐藏继承的final方法,final方法的行为不允许子类纂改。145.7 5.7 对象的上转型对象对象的上转型对象 假设,B是A的子类或间接子类,当我们用子类B创建一个对象,并把这个对象的引用放到类A声明的对象中时,如 A a;A a;B b=new B();B
12、 b=new B();a=b;a=b;那么,就称对象a是子类对象b的上转型对象.上转型对象不能操作子类声明定义的成员变量(失掉了这部分属性),不能使用子类声明定义的方法(失掉了一些功能)。上转型对象可以代替子类对象去调用子类重写的实例方法。如果子类重写的方法是实例方法,那么上转型对象调用重写的方法时,就是通知对应的子类对象去调用这些方法。因此,如果子类重写了父类的某个实例方法后,子类对象的上转型对象调用这个方法时,一定是调用了这个重写的方法。上转型对象可以调用子类继承的成员变量和隐藏的成员变量。可以将对象的上转型对象再强制转换到一个子类对象,这时该子类对象又具备了子类的所有属性和功能。例子5-
13、8中,使用了上转型对象,效果 如图5.1015例子5-8 效果图165.8 5.8 继承与多态继承与多态 和继承有关的多态性是指父类的某个方法被其子类重写时,可和继承有关的多态性是指父类的某个方法被其子类重写时,可以产生自己的功能行为以产生自己的功能行为,即同一个操作被不同类型对象调用时可能产生不同的行为。例如,狗和猫都具有哺乳类的功能:“叫声”,当狗操作“叫声”时产生的声音是“汪汪,而猫操作“叫声”时产生的声音是“喵喵”,这就是“叫声”的多态。当一个类有很多子类时,并且这些子类都重写了父类中的某个方法。当我们把子类创建的对象的引用放到一个父类的对象中时,就得到了该对象的一个上转型对象,那么这
14、个上转型对象在调用这个方法时就可能具有多种形态。因为不同的子类在重写父类的方法时可能产生不同的行为。也就是说,不同对象的上转型对象调用同一方法可能产生不同的行为。例子5-9,程序的运行结果如图5.11.175.9 5.9 抽象类抽象类 用关键字abstract修饰的类称为abstract类(抽象类)。如:abstract class Aabstract class A abstract类有如下特点:1 1abstractabstract类中可以有类中可以有abstractabstract方法方法 和普通的类相比,abstract类可以有abstract方法(抽象方法)也可以有非abstract
15、方法。对于abstract方法,只允许声明,不允许实现,而且不允许使用final和abstract同时修饰一个方法。2 2abstractabstract类不能用类不能用newnew运算创建对象运算创建对象 对于abstract类,我们不能使用new运算符创建该类的对象。3 3做上转型对象做上转型对象 尽管abstract类不能创建对象,但它的非abstract子类必须要重写它中的全部abstract方法,这样一来,就可以让abstract类声明的对象成为其子类对象的上转型对象,并调用子类重写的方法。注:注:abstract类也可以没有abstract方法。注:注:如果一个abstract类是
16、abstract类的子类,它可以重写父类的abstract方法,也可以继承这个abstract方法。185.105.10 面向抽象面向抽象 设计一个Pillar类,通过用Pillar类创建的对象计算各种柱体的体积(不尽合理)。面向抽象的核心思想如下:(1)抽象细节)抽象细节 面向抽象的第一步就是将经常需要变化的部分分割出来,将其作为abstract类的中的abstract方法,不让设计者去关心实现的细节,避免所设计的类依赖于这些细节。把Pillar类中计算底面积的算法作为下列abstract类Geometry的abstract方法 (2)面向抽象设计类)面向抽象设计类 面向抽象编程的第二步就是
17、面向抽象类来设计一个新的Pillar类。Geometry的子类Lader和Cirlce重写了Geometry类的getArea()方法,给出了各自计算面积的算法细节。例子5-10计算具有Cirlce底和Lader底的柱体的体积了,程序的运行结果如图5.12.19面向抽象设计一个体现开面向抽象设计一个体现开-闭原理的类闭原理的类 Pillar类将自己经常需要变化的细节分割出来,作为absrtact类A中的abstract方法,然后面向Geometry类来设计Pillar类,即Pillar类含有Geomerty类声明的对象obj,那么obj对象可以调用Geometry的子类重写的getArea()
18、方法计算面积,使得PillarPillar类的设计不依赖抽象类类的设计不依赖抽象类GeometryGeometry的子类的子类,当程序再增加一个Geometry类的子类时,Pillar类不需要做任何修改。为了满足“开-闭”原理,在程序设计好后,首先对abstract类的修改修改“关关闭闭”,否则,一旦修改abstract类,比如,为它再增加一个abstract方法,那么abstract类所有的子类都需要做出修改。程序设计好后,应当对增加对增加abstract类类的子类的子类“开放开放”,即在程序中再增加子类时,不需要修改其它重要的类,即所谓对扩展开放对扩展开放。205.11 5.11 接口接口
19、 Java不支持多继承性,即一个类只能有一个父类。单继承性使得Java简单,易于管理程序。为了克服单继承的缺点,Java使用了接口,一个类可以实现多个接口。使用关键字interface来定义一个接口。分为接口的声明和接口体。211 1接口的声明与使用接口的声明与使用(1 1)接口声明)接口声明:接口通过使用关键字interface来声明,格式:interface interface 接口的名字接口的名字 (2 2)接口体)接口体:接口体中包含常量定义和方法定义两部分。接口体中只进行方法的声明,不许提供方法的实现,所以,方法的定义没有方法体,且用分号“;”结尾。interface Printab
20、leinterface Printable final int MAX=100;final int MAX=100;void add();void add();float sum(float x,float y);float sum(float x,float y);(3 3)接口的使用)接口的使用:一个类通过使用关键字implements 声明自己实现一个或多个接口。如果实现多个接口,用逗号隔开接口名,如:class A implements Printableclass A implements Printable,AddableAddable22关于使用接口的规则关于使用接口的规则 如果
21、一个类实现某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体。要注意的是,接口中的方法被默认是public和abstract的,接口在声明方法时可以省略方法前面的public和abstract关键字,但是,类在实现接口方法时,一定要用public来修饰。类实现的接口方法以及接口中的常量可以被类的对象调用。如果父类实现了某个接口,则其子类也就自然实现这个接口。接口也可以被继承,即可以通过关键字extends声明一个接口是另一个接口的子接口。阅读例子5-11,来看一看类 是如何实现接口的。232 2接口与多态接口与多态 一个类可以实现多个接口,接口可以增加很多类都需要实现的功能,
22、不同的类可以使用相同的接口,同一个类也可以实现多个接口。如,轿车、飞机、轮船等,可能也需要具体实现“收取费用”和“调节温度”的功能,而它们的父类可能互不相同。接口只关心功能,并不关心功能的具体实现,使用同一接口的类在实现接口中的方法时,可以给出不同的方法体。如“客车类”实现一个接口,该接口中有一个“收取费用”的方法,那么这个“客车类”必须具体给出怎样收取费用的操作,即给出方法的方法体,不同车类都可以实现“收取费用”,但“收取费用”的手段可能不相同,这是功能“收取费用”的多态,即不同对象调用同一操作可能具有不同的行为。接口的思想在于它可以增加很多类都需要实现的功能,使用相同的接口类不一定有继承关
23、系。245.12 5.12 接口的回调接口的回调 复习:复习:在讲述继承与多态时,我们通过子类对象的上转型体现了继承的多态性,即把子类创建的对象的引用放到一个父类的对象中时,得到该对象的一个上转型对象,那么这个上转型对象在调用方法时就可能具有多种形态,不同对象的上转型对象调用同一方法可能产生不同的行为。1 1接口回调接口回调 接口回调是多态的另一种体现。接口回调是指:可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量中,那么该接口变量就可以调用被类实现的接口中的方法,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,这一过程称作对象功能的接口回调。接口回调可
24、能产生不同的行为。例5-12使用了接口的回调技术(效果如图5.15所示)。2 2接口做参数接口做参数 当一个方法的参数是一个接口类型时,如果一个类实现了该接口,那么就可以把该类的实例的引用传值给该参数,参数可以回调类实现的接口方法。例5-13中接口做某些方法的参数(效果如图5.16所示)。255.13 5.13 面向接口面向接口 可以通过在接口中声明若干个abstract方法,表明这些方法的重要性,方法体的内容细节由实现接口的类去完成。使用接口进行程序设计的核心思想是使用接口回调,即接口变量存放实现该接口的类的对象的引用,从而接口变量就可以回调类实现的接口方法。面向接口也可以体现程序设计的“开
25、-闭”原理(Open-Closed Principle),即对扩展开放,对修改关闭。26面向接口设计一个体现开面向接口设计一个体现开-闭原理的类闭原理的类 Pillar类将自己经常需要变化的细节分割出来,作为接口Geometry中的abstract方法,然后面向接口Geometry来设计Pillar类,即Pillar类把Geometry定义的接口变量作为其中的成员。从图5.17可以看出,当程序再增加一个实现接口Geometry的D类时,接口变量所在的Pillar类不需要做任何修改,接口变量就可以回调D类实现的接口方法。例5-14使用了接口的回调技术(效果如图5.18所示)。27例子5-14 效
26、果图例5-14使用了接口的回调技术(效果如图5.18所示)285.14 5.14 抽象类与接口的比较抽象类与接口的比较 n1抽象类抽象类类和接口都可以有抽象类抽象类方法。n2接口中只可以有常量,不能有变量;而抽象抽象类类类中即可以有常量也可以有变量。n3抽象类抽象类类中也可以有非抽象类抽象类方法,接口不可以。295.15 5.15 内部类内部类 我们已经知道:类可以有两种重要的成员:成员变量和方法,类还可以有一种成员:内部类。Java支持在一个类中声明另一个类,这样的类称作内部类,而包含内部类的类成为内部类的外嵌类。内部类同类中声明的方法或成员变量一样,一个类把内部类看作是自己的成员。外嵌类的
27、成员变量在内部类中仍然有效,内部类中的方法也可以调用外嵌类中的方法。内部类的类体中不可以声明类变量和类方法。外嵌类可以用内部类声明对象,作为外嵌类的成员。例子5-15更好的了解内部类,效果如图5-19。305.16 5.16 匿名类匿名类 1 1和类有关的匿名类和类有关的匿名类 当使用类创建对象时,程序允许我们把类体与对象的创建组合在一起,也就是说,类创建对象时,除了构造方法还有类体,此类体被认为是该类的一个子类去掉类声明后的类体,称作匿名类。匿名类就是一个子类,由于无名可用,所以不可能用匿名类声明对象,但却可以直接用匿名类创建一个对象。假设Hello是类,那么下列代码就是用Hello的一个子
28、类(匿名类)创建对象:new Hello()new Hello()匿名类的类体匿名类的类体 匿名类可以继承类的方法也可以重写类的方法。我们使用匿名类时,必然是在某个类中直接用匿名类创建对象,因此匿名类一定是内部类,匿名类可以访问外嵌类中的成员变量和方法,匿名类不可以声明static成员变量和static方法。匿名类的主要用途就是向方法的参数传值。例子5-16展示了匿名类的用法,效果如图5-20所示。312 2和接口有关的匿名类和接口有关的匿名类 假设Computable是一个接口,那么,Java允许直接用接口名和一个类体创建一个匿名对象,此类体被认为是实现了Computable接口的类去掉类声
29、明后的类体,称作匿名类。下列代码就是用实现了Computable接口的类(匿名类)创建对象:new Computable()new Computable()实现接口的匿名类的类体实现接口的匿名类的类体 如果某个方法的参数是接口类型,那么我们可以使用接口名和类体组合创建一个匿名对象传递给方法的参数,类体必须要实现接口中的全部方法。例子5-17展示了和接口有关的匿名类的用法,效果如图5.21所示。325.17 5.17 异常类异常类 所谓异常就是程序运行时可能出现一些错误,比如试图打开一个根本不存在的文件等,异常处理将会改变程序的控制流程,让程序有机会对错误作出处理。当程序运行出现异常时,Java
30、运行环境就用异常类异常类ExceptionException的相应子类创建一个异常对象,并等待处理Java使用trycatch语句来处理异常,将可能出现的异常操作放在trycatch语句的try部分,当try部分中的某个语句发生异常后,try部分将立刻结束执行,而转向执行相应的catch部分.1 1trycatch语句语句 格式如下:trytry 包含可能发生异常的语句包含可能发生异常的语句 catch(ExceptionSubClass1 e)catch(ExceptionSubClass1 e)catch(ExceptionSubClass2 e)catch(ExceptionSubCla
31、ss2 e)各个catch参数中的异常类都是Exception的某个子类,表明try部分可能发生的异常,这些子类之间不能有父子关系,否则保留一个含有父类参数的catch即可。例子5-18,给出了try-catch语句 的用法(效果如图5.22所示)33 2自定义异常类 我们也可以扩展Exception类定义自己的异常类,然后规定哪些方法产生这样的异常。一个方法在声明时可以使用throws关键字声明抛出所要产生的若干个异常,并在该方法的方法体中具体给出产生异常的操作,即用相应的异常类创建对象,这将导致该方法结束执行并抛出所创建的异常对象。程序必须在trycatch块语句中调用抛出异常的方法。例5
32、-19中(效果如图5.23所示),用一个方法求偶正数的平方根。我们自己定义了一个异常类,当向该方法传递的参数是负数时发生MyException。345.18 5.18 泛型类泛型类 泛型(Generics)是Sun公司在SDK1.5中推出的,其主要目的是可以建立具有类型安全的集合框架,如链表、散列映射等数据结构,关于这一点我们将在第7章讨论。1 1泛型类声明泛型类声明 可以使用“class 名称”声明一个类,为了和普通的类有所区别,这样声明的类称作泛型类,如:class Aclass A 其中A是泛型类的名称,E是其中的泛型,也就是说我们并没有指定E是何种类型的数据,它可以是任何对象或或接口,
33、但不能是基本类型数据。class Chorus 泛型类声明时,“泛型列表”给出的泛型可以作为类的成员变量的类型、方法的类型以及局部变量的类型。泛型类的类体和普通类的类体完全类似,由成员变量和方法构成,如class Chorusclass Chorus void makeChorus(E person,F yueqi)void makeChorus(E person,F yueqi)yueqi.toString();yueqi.toString();person.toString();person.toString();352使用泛型类声明对象 使用泛型类声明对象时,必须要指定类中使用的泛型的具
34、体实际类型。例如:Chorus modelChorus model model =new Chorus()model =new Chorus();例5-20,假设要实现“歌手”和“乐器”的和声,我们用上面的Chorus泛型类创建一个基于“歌手”和“乐器”的对象(效果如图5.24所示)。泛型类中的泛型数据personperson和和yueqiyueqi只能调用类Object中的方法,因此“学生类”和“乐器类”都重写了类Object的toString()方法。例5-21(效果如图5.25所示)声明了一个泛型类锥,一个锥对象计算体积时,只关心它的“底”是否能计算面积,并不关心“底”的类型。36 3泛
35、型接口 可以使用“interface 名称”声明一个接口,这样声明的接口称为泛型接口interface Computerinterface Computer其中,Computer是泛型接口的名称,E是其中的泛型。泛型类可以使用泛型接口。例5-22,效果如图5.26所示。Java泛型的主要目的是可以建立具有类型安全的数据结构,如链表、散列表等数据结构,最最重要的一个优点就是:重要的一个优点就是:在使用这些泛型类建立的数据结构时,不必进行强制类型转换,即不要求进行运行时类型检查。SDK 1.5是支持泛型的编译器,它将运行时类型检查提前到编译时执行,使代码更安全。375.15 5.15 泛型类泛型类 Java泛型的主要目的是可以建立具有类型安全的数据结构,如链表、散列表等数据结构,最重要的一个优点就是:在使用这些泛型类建立的数据结构时,不必进行强制类型转换,即不要求进行运行时类型检查。SDK1.5是支持泛型的编译器,它将运行时类型检查提前到编译时执行,使代码更安全。返回返回3839
侵权处理QQ:3464097650--上传资料QQ:3464097650
【声明】本站为“文档C2C交易模式”,即用户上传的文档直接卖给(下载)用户,本站只是网络空间服务平台,本站所有原创文档下载所得归上传人所有,如您发现上传作品侵犯了您的版权,请立刻联系我们并提供证据,我们将在3个工作日内予以改正。