Java的多态性,抽象类与接口_第1页
Java的多态性,抽象类与接口_第2页
Java的多态性,抽象类与接口_第3页
Java的多态性,抽象类与接口_第4页
Java的多态性,抽象类与接口_第5页
已阅读5页,还剩59页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

继承是指从一个父类(父类)派生出派生类(子类)的过程;继承使用关键字extends;对于类成员,可以使用public、protected、缺省和private这4种访问权限修饰符;对于类,可以使用public和缺省这2个访问权限;创建子类实例时,必须先执行父类的构造方法,然后再执行子类的构造方法;super关键字有两种主要用途,都与父类有关。回顾目前一页\总数六十四页\编于十四点为什么使用多态?宠物生病了,需要主人给宠物看病不同宠物看病过程不一样不同宠物恢复后体力值不一样

打针

吃药

吃药

疗养

狗狗

Q仔

目前二页\总数六十四页\编于十四点为什么使用多态?编码实现publicclassMaster{publicvoidCure(Dogdog){if(dog.getHealth()<50){dog.setHealth(60);System.out.println("打针、吃药");}}publicvoidCure(Penguinpenguin){if(penguin.getHealth()<50)penguin.setHealth(70);System.out.println("吃药、疗养");}}

主人类……Mastermaster=newMaster();master.Cure(dog);master.Cure(penguin);……

测试方法目前三页\总数六十四页\编于十四点为什么使用多态?如果又需要给XXX看病,怎么办?添加XXX类,继承Pet类修改Master类,添加给XXX看病的方法使用多态优化设计频繁修改代码,代码可扩展性、可维护性差目前四页\总数六十四页\编于十四点为什么使用多态?使用多态优化后的代码……Petpet=newDog();Mastermaster=newMaster();master.Cure(pet);……

测试方法publicclassDogextendsPet{publicvoidtoHospital(){this.setHealth(60);System.out.println("打针、吃药");}}publicclassPenguinextendsPet{publicvoidtoHospital(){

this.setHealth(70);System.out.println("吃药、疗养");}}publicclassMaster{publicvoidCure(Petpet){if(pet.getHealth()<50)pet.toHospital();}}

主人类Dog类Penguin类1234又要给XXX看病时,只需:1.编写XXX类继承Pet类(旧方案也需要)2.创建XXX类对象(旧方案也需要)3.其他代码不变(不用修改Master类)目前五页\总数六十四页\编于十四点什么是多态?生活中的多态你能列举出一个多态的生活示例吗?程序中的多态同一个引用类型,使用不同的实例而执行不同操作父类引用,子类对象同一种事物,由于条件不同,产生的结果也不同目前六页\总数六十四页\编于十四点多态性(polymorphism)概念:是面向对象程序设计的另一个重要特征,其基本含义是“拥有多种形态”,具体指在程序中用相同的名称来表示不同的含义。例如:用同一方法名来表示不同的操作。类型:有两种静态多态性:包括变量的隐藏、方法的重载动态多态性:在编译时不能确定调用方法,只有在运行时才能确定调用方法,又称为运行时的多态性。7目前七页\总数六十四页\编于十四点静态多态静态多态也称为编译时多态,即在编译时决定调用哪个方法;静态多态一般是指方法重载;只要构成了方法重载,就可以认为形成了静态多态的条件;静态多态与是否发生继承没有必然联系。目前八页\总数六十四页\编于十四点动态多态动态多态也称为运行时多态,即在运行时才能确定调用哪个方法;形成动态多态必须具体以下条件:必须要有继承的情况存在;在继承中必须要有方法覆盖;必须由父类的引用指向派生类的实例,并且通过父类的引用调用被覆盖的方法;由上述条件可以看出,继承是实现动态多态的首要前提。目前九页\总数六十四页\编于十四点下面主要介绍动态多态性//多态性的例子classAnimal{

publicvoidroar(){ System.out.println("动物:..."); }}classCatextendsAnimal{

publicvoidroar(){ System.out.println("猫:喵,喵,喵,..."); }}classDogextendsAnimal{

publicvoidroar(){ System.out.println("狗:汪,汪,汪,..."); }}10目前十页\总数六十四页\编于十四点//多态性的例子(续)publicclassAnimalTest{ publicstaticvoidmain(Stringargs[]){ Animalam=newAnimal();

am.roar(); am=newDog();

am.roar(); am=newCat();

am.roar(); }}程序运行结果:动物:...狗:汪,汪,汪,...猫:喵,喵,喵,... 根据对象的赋值规则,可以把子类对象赋给父类对象名,这是允许。当用同一形式:

父类对象名.roar()

去调用时,能够根据子类对象的不同,得到不同的结果,这就是多态性。11目前十一页\总数六十四页\编于十四点实现多态的流程用多态实现打印机分为黑白打印机和彩色打印机不同类型的打印机打印效果不同黑白打印机彩色打印机打印目前十二页\总数六十四页\编于十四点实现多态的设计思路使用多态实现思路编写父类编写子类,子类重写(覆盖)父类方法运行时,使用父类的类型,子类的对象计算机可以连接各种打印机无论连接何种打印机打印方法都相同根据连接打印机不同,效果也不同目前十三页\总数六十四页\编于十四点实现多态

编码实现实现多态的两个要素:1.方法重写2.使用父类类型classPrinter{

print(Stringstr);}classColorPrinterextendsPrinter{

print(Stringstr)

{System.out.println("输出彩色的"+str);}}classBlackPrinterextendsPrinter{

print(Stringstr)

{System.out.println("输出黑白的"+str);}}publicstaticvoidmain(String[]args){

Printerp=newColorPrinter();p.print();p=newBlackPrinter();p.print();}父类子类运行同一种操作方式,不同的操作对象只能调用父类已经定义的方法继承是子类使用父类的方法,而多态则是父类使用子类的方法。(把父类当做子类来用)目前十四页\总数六十四页\编于十四点方法重写(覆盖)方法重写的规则在继承关系的子类中重写的方法名、参数、返回值类型必须与父类相同私有方法不能继承因而也无法重写

位置方法名参数表返回值访问修饰符方法重写子类相同相同相同不能比父类更严格方法重载同类相同不相同无关无关方法重写override方法重载overload

VS目前十五页\总数六十四页\编于十四点实现运行时多态技术的条件:有一个继承层次关系;在子类中重写父类的方法;通过父类的引用对子类对象进行调用。采用多态技术的优点: 引进多态技术之后,尽管子类的对象千差万别,但都可以采用父类引用.方法名([参数])统一方式来调用,在程序运行时能根据子对象的不同得到不同的结果。这种“以不变应万变”的形式可以规范、简化程序设计,符合软件工程的“一个接口,多种方法”思想。

16目前十六页\总数六十四页\编于十四点多态的运行机制多态的运行机制

Java多态机制是基于“方法绑定(binding)”,就是建立methodcall(方法调用)和methodbody(方法本体)的关联。如果绑定动作发生于程序执行前(由编译器和连接器完成),称为“先期绑定”。对于面向过程的语言它们没有其他选择,一定是先期绑定。比如C编译器只有一种methodcall,就是先期绑定。(C++有先期联编和后期联编)

当有多态的情况时,解决方案便是所谓的后期绑定(latebinding):绑定动作将在执行期才根据对象型别而进行。后期绑定也被称为执行期绑定(run-timebinding)或动态绑定(dynamicbinding)。Java的所有方法,除了被声明为final者,都使用后期绑定。将方法声明为final型可以有效防止他人覆写该函数。但是或许更重要的是,这么做可以“关闭”动态绑定。或者说,这么做便是告诉编译器:动态绑定是不需要的。于是编译器可以产生效率较佳的程序代码。目前十七页\总数六十四页\编于十四点引用转型父类的引用可以指向子类的对象,如:

BaseClassobj=newDerivedClass();

这样的语句是合法的;但是子类的引用则不可以指向父类的对象,如:

DerivedClassobj=newBaseClass();

这样的语句将引发错误。目前十八页\总数六十四页\编于十四点引用转型示例classPerson{//定义人类

……}classStudentextendsPerson{//学生类继承于人类

……}public

classOverriddenDemo{

public

static

voidmain(String[]args){

//正确,所有的学生一定是人

Personper=newStudent();

//错误,并不是所有的人都是学生

Studentstd=newPerson();}}目前十九页\总数六十四页\编于十四点多态性实例分析Example例如动物园的饲养员能够给各种各样的动物喂食。

图1显示了饲养员Feeder、食物Food和动物Animal以及它的子类的类框图。目前二十页\总数六十四页\编于十四点多态性实例分析

图1饲养员Feeder、食物Food和动物Animal以及它的子类的类框图目前二十一页\总数六十四页\编于十四点多态性实例分析可以把Feeder、Animal和Food都看成独立的子系统。Feeder类的定义如下:

publicclassFeeder{

publicvoidfeed(Animalanimal,Foodfood){

animal.eat(food);

}

}以下程序演示一个饲养员分别给一只狗喂肉骨头,给一只猫喂鱼。

Feederfeeder=newFeeder();

Animalanimal=newDog();

Foodfood=newBone();

feeder.feed(animal,food);

animal=newCat();

food=newFish();

feeder.feed(animal,food);

//给狗喂肉骨头//给猫喂鱼目前二十二页\总数六十四页\编于十四点多态性实例分析Java语言允许某个类型的引用变量引用子类的实例,而且可以对这个引用变量进行类型转换:Animalanimal=newDog();

Dogdog=(Dog)animal;

Creaturecreature=animal;

如图2所示,如果把引用变量转换为子类类型,称为向下转型,如果把引用变量转换为父类类型,称为向上转型。在进行引用变量的类型转换时,会受到各种限制。而且在通过引用变量访问它所引用的实例的静态属性、静态方法、实例属性、实例方法,以及从父类中继承的方法和属性时,Java虚拟机会采用不同的绑定机制。

//向下转型,把Animal类型转换为Dog类型

//向上转型,把Animal类型转换为

Creature类型目前二十三页\总数六十四页\编于十四点多态

图2类型转换目前二十四页\总数六十四页\编于十四点多态性实例分析下面通过具体的例子来演示多态的各种特性。在下面的例程中,Base父类和Sub子类中都定义了实例变量var、实例方法method()、静态变量staticVar和静态方法staticMethod(),此外,在Sub类中还定义了实例变量subVar和subMethod()。Sub.java

packagepoly;

classBase{

Stringvar="BaseVar";

staticStringstaticVar="StaticBaseVar";

voidmethod(){

System.out.println("Basemethod");

}

staticvoidstaticMethod(){System.out.println("StaticBasemethod");

}

}//成员(实例)变量//静态变量//成员(实例)方法//静态方法

目前二十五页\总数六十四页\编于十四点publicclassSubextendsBase{

Stringvar=“SubVar”;

//成员(实例)变量

staticStringstaticVar="StaticSubVar";

//静态变量voidmethod(){

//覆盖父类的method()方法

System.out.println("Submethod");

}

staticvoidstaticMethod(){

//隐藏父类的staticMethod()方法

System.out.println("StaticSubmethod");

}StringsubVar="VaronlybelongingtoSub";

voidsubMethod(){

System.out.println("MethodonlybelongingtoSub");

}

publicstaticvoidmain(Stringargs[]){

Basewho=newSub();

//who被声明为Base类型,引用Sub实例

System.out.println("who.var="+who.var);

System.out.println("who.staticVar="+who.staticVar);

who.method();

who.staticMethod();

}

}//打印Base类的var变量//打印Base类的staticVar变量//打印Sub实例的method()方法//打印Base类的staticMethod()方法目前二十六页\总数六十四页\编于十四点多态的一些细节(1)对于一个引用类型的变量,Java编译器按照它声明的类型来处理。例如在以下代码中,编译器认为who是Base类型的引用变量,不存在subVar成员变量和subMethod()方法,所以编译出错:Basewho=newSub();

//who是Base类型

who.subVar=“123”;

//编译出错,提示在Base类中没有subVar属性

who.subMethod();

//编译出错,提示在Base类中没有subMethod()方法如果要访问Sub类的成员,必须通过强制类型的转换:

Basewho=newSub();

//who是Base类型

((Sub)who).subVar="123";

//编译成功,把Base引用类型强制转换为Sub引用类型

((Sub)who).subMethod();

//编译成功,把Base引用类型强制转换为Sub引用类型目前二十七页\总数六十四页\编于十四点多态的一些细节Java编译器允许具有直接或间接继承关系的类之间进行类型转换.对于向上转型,不必使用强制类型转换,因为子类的对象肯定也可看作父类的对象。例如一个Dog对象是一个Animal对象,也是一个Creature对象,也是一个Object对象:Dogdog=newDog();

Creaturecreature=dog;

//编译成功,把Dog引用类型直接转换为Creature引用类型

Objectobject=dog;

//编译成功,把Dog引用类型直接转换为Object引用类型对于向下转型,必须进行强制类型转换:Creaturecreature=newCat();

Animalanimal=(Animal)creature;

//编译成功,把Creature引用类型强制转换为Animal引用类型

Catcat=(Cat)creature;

//编译成功,把Creature引用类型强制转换为Cat引用类型

Dogdog=(Dog)creature;

//编译成功,把Creature引用类型强制转换为Dog引用类型目前二十八页\总数六十四页\编于十四点多态的一些细节假如两种类型之间没有继承关系,即不在继承树的同一个继承分支上,那么Java编译器不允许进行类型转换,例如:

Dogdog=newDog();

Catcat=(Cat)dog;

//编译出错,不允许把Dog引用类型转换为Cat引用类型(2)对于一个引用类型变量,运行时Java虚拟机按照它实际引用的对象来处理。例如以下代码虽然编译可以通过,但运行时会抛出ClassCastException运行时异常:Basewho=newBase();

//who引用Base类的实例

Subs=(Sub)who;

//运行时抛出ClassCastException

在运行时,子类的对象可以转换为父类类型,而父类的对象实际上无法转换为子类类型。因为通俗的讲,父类拥有的成员子类肯定也有,而子类拥有的成员父类不一定有。目前二十九页\总数六十四页\编于十四点多态的一些细节假定Java虚拟机能够把子类对象转换为父类类型,那么以下代码中的sub.subMethod()方法无法执行:

Basewho=newBase();

//who引用Base类的实例

Subsub=(Sub)who;

//假定运行时未出错

sub.subMethod();

//sub引用变量实际上引用Base实例,而Base实例没有subMethod()方法

由此可见,在运行时,Java虚拟机无法把子类对象转变为父类类型。以下代码尽管能够编译成功,但在运行时,creature变量引用的Cat对象无法转变为Dog类型,因此会抛出ClassCastException:

Creaturecreature=newCat();

Animalanimal=(Animal)creature;

//运行正常,Cat对象可转换为Animal类型

Catcat=(Cat)creature;

//运行正常,Cat对象可以被Cat类型的引用变量引用

Dogdog=(Dog)creature;

//运行时抛出ClassCastException,Cat对象不可转换为Dog类型(但是会编译成功)目前三十页\总数六十四页\编于十四点(3)在运行时环境中,通过引用类型变量来访问所引用对象的方法和属性时,Java虚拟机采用以下绑定规则:

1)成员(实例)方法与引用变量实际引用的对象的方法绑定,这种绑定属于动态绑定,因为是在运行时由Java虚拟机动态决定的。

2)静态方法与引用变量所声明的类型的方法绑定,这种绑定属于静态绑定,因为实际上是在编译阶段就已经作了绑定。

3)成员变量(包括静态变量和实例变量)与引用变量所声明的类型的成员变量绑定,这种绑定属于静态绑定,因为实际上是在编译阶段就已经作了绑定。多态的一些细节目前三十一页\总数六十四页\编于十四点例如,对于以下这段代码:

Basewho=newSub();

//who被声明为Base类型,引用Sub实例对象

System.out.println("who.var="+who.var);

//打印Base类的var变量

System.out.println("who.staticVar="+who.staticVar);

//打印Base类的staticVar变量

who.method();

//打印Sub实例的method()方法

who.staticMethod();

//打印Base类的staticMethod()方法

运行时将会输出如下结果:

who.var=BaseVar

who.staticVar=StaticBaseVar

Submethod

StaticBasemethod多态的一些细节目前三十二页\总数六十四页\编于十四点再看一个例子:

publicabstractclassA{

abstractvoidmethod();

voidtest(){

method();

//到底调用哪个类的mehtod()方法?

}

}

publicclassBextendsA{

voidmethod(){

//覆盖父类的method()方法

System.out.println("Sub");

}

publicstaticvoidmain(Stringargs[]){

newB().test();

}

}多态的一些细节目前三十三页\总数六十四页\编于十四点运行类B的main()方法将打印"Sub"。方法test()在父类A中定义,它调用了方法method()。虽然方法method()在类A中被定义为是抽象的,它仍然可以被调用,因为在运行时环境中,Java虚拟机会执行类B的实例的method()方法。一个实例所属的类肯定实现了父类中所有的抽象方法(否则这个类不能被实例化)。再看一个例子:

publicclassA{

voidmethod(){System.out.println("Base");}

voidtest(){method();}

}

publicclassBextendsA{

voidmethod(){System.out.println("Sub");}publicstaticvoidmain(Stringargs[]){

newA().test();//调用类A的method()方法

newB().test();

//调用类B的method()方法

}

多态的一些细节目前三十四页\总数六十四页\编于十四点运行这段代码将打印:

Base

Subtest()方法在父类A中定义,它调用了method()方法,和上面一个例子的区别是父类A的method()方法不是抽象的。但是通过newB().test()调用method()方法,执行的仍然是子类B的method()方法。由此可以更深入地体会动态绑定的思想:在运行环境中,当通过B类的实例去调用一系列的实例方法(包括一个方法调用的另一个方法),将优先和B类本身包含的实例方法动态绑定,如果B类没有定义这个实例方法,才会和从父类A中继承来的实例方法动态绑定。多态的一些细节目前三十五页\总数六十四页\编于十四点instanceof运算符:功能:用于判断一个类是否实现接口,也可用来判断一个对象是否属于一个类。格式:对象instanceof类或接口结果:true或false//程序片断Personp=newPerson();Students=newStudent();System.out.println("人:p");System.out.println("学生:s");System.out.println("sinstanceofStudent:"+(sinstanceofStudent));System.out.println("sinstanceofPerson:"+(sinstanceofPerson));System.out.println("pinstanceofPerson:"+(pinstanceofPerson)); System.out.println("pinstanceofStudent:"+(pinstanceofStudent));程序运行结果:人:p学生:ssinstanceofStudent:truesinstanceofPerson:truepinstanceofPerson:truepinstanceofStudent:false36目前三十六页\总数六十四页\编于十四点instanceof运算符在强制类型转换之前通过instanceof运算符检查对象的真实类型,可以避免类型转换异常,从而提高代码健壮性对象instanceof

类或接口/***测试instanceof运算符的使用。*/publicclassTestPoly2{publicstaticvoidmain(String[]args){Petpet=newPenguin(“Q仔”,“QQ企鹅");//Petpet=newDog(“旺财”,“土狗");pet.eat();if(petinstanceofDog){Dogdog=(Dog)pet;dog.catchingFlyDisc();}elseif(petinstanceofPenguin){Penguinpgn=(Penguin)pet;pgn.swimming();}}}/***测试instanceof运算符的使用。*/publicclassTestPoly2{publicstaticvoidmain(String[]args){//Petpet=newPenguin(“Q仔”,“QQ企鹅");Petpet=newDog(“旺财”,“土狗");pet.eat();if(petinstanceofDog){Dogdog=(Dog)pet;dog.catchingFlyDisc();}elseif(petinstanceofPenguin){Penguinpgn=(Penguin)pet;pgn.swimming();}}}注释创建Penguin对象语句,取消创建Dog对象语句的注释目前三十七页\总数六十四页\编于十四点回顾继承:继承目前三十八页\总数六十四页\编于十四点导入:为什么使用抽象类?如果我们想访问调用子类Dog的print()方法。以下代码有什么问题?Java中也使用抽象类,限制实例化Petpet=newPet();pet.print();实例化Pet没有意义publicabstractclassPet{

}

通过抽象类来改进实现目前三十九页\总数六十四页\编于十四点导入:为什么使用抽象方法?如果父类的方法没机会被访问调用,以下代码有什么问题?◎可以使用抽象方法来优化抽象方法没有方法体抽象方法必须在抽象类里抽象方法必须在子类中被实现,除非子类是抽象类publicabstractvoidprint();没有方法体publicabstractclassPet{

publicvoidprint(){//…}}每个子类的print()方法实现不同,父类print()方法的实现是多余的。目前四十页\总数六十四页\编于十四点抽象类(abstract)引例

抽象是面向对象的一种重要方法,通过抽象我们能够设计一个更普通、更通用的类,例:从许许多多学生中,抽象出Student类,再从学生、工人、农民、…抽象出Person类。

下面,我们来分析一个例子:Shape类(周长、面积)Circle类(周长、面积)Rect类(周长、面积)

Shape类是假想出的共同父类,现实中不存在叫“形状”的东西,若去实例化这样的对象很勉强。为阻止生成Shape类对象,可以将该类声明为抽象类。

41目前四十一页\总数六十四页\编于十四点抽象方法与抽象类

关键字abstract可用来修饰方法和类,表示“尚未实现”的含义:如果方法的声明中使用了abstract修饰符,那么该方法就称为抽象方法。这表示该类中不提供方法的实现,即不定义方法体。格式:访问权限abstract返回类型方法名([参数表]);//无方法体例如:将前面Shape类的两个方法声明为抽象方法:

publicabstractdoublegetArea();

publicabstractdoublegetPerimeter();注意:◎无方法体与方法体为空是两个不同的概念。42目前四十二页\总数六十四页\编于十四点如果一个类的声明中有abstract修饰符,那么该类就成为抽象类。格式:[访问权限]abstractclass类名{……}例如:将前面Shape类声明为抽象类: abstractclassShape{……}◎说明:抽象类不能进行实例化,否则出现编译错误;通常,一个抽象类至少定义一个抽象方法,但并不是说非要定义一个抽象方法,即使类体没有一个抽象方法也是允许;当一个类中包含有抽象方法时,该类一定要声明为抽象类;43目前四十三页\总数六十四页\编于十四点◎说明:(续)当子类继承了一个抽象类时,必须实现该抽象类中定义的全部抽象方法,否则必须声明为抽象类;当类实现了一个接口,但并没有实现该接口的所有方法时,该类必须声明为抽象类,否则出错;抽象方法不能被private、final或static修饰。为什么? (抽象方法必须被子类所覆盖,如果说明为private,则外部无法访问,覆盖也无从谈起。若说明为Static,即是不创建对象也能访问:类名.方法名()

,这要求给出方法体,但与抽象方法的定义相矛盾。)问题:以下哪个是抽象方法的正确形式?(1)abstarctvoidexample()(2)abstarctvoidexample(){}(3)staticabstarctvoidexample()(4)finalabstarctvoidexample()(1)44目前四十四页\总数六十四页\编于十四点抽象类与具体类的比较

45目前四十五页\总数六十四页\编于十四点抽象类引用

◎虽然不能实例化抽象类,但可以创建它的引用。Java支持多态性,允许通过父类引用来引用类的对象。//使用抽象类引用的例子abstractclassA{ //抽象类 abstractvoidm1(); //抽象方法}classBextendsA{

voidm1(){

System.out.println("Inm1.");} //实现了m1()方法 voidm2(){

System.out.println("Inm2.");

}} publicclassAbstractRef{ publicstaticvoidmain(Stringargs[]){ Bb=newB();

Aa=b; //父类引用 a.m1(); }}程序运行结果:Inm1.46目前四十六页\总数六十四页\编于十四点接口(interface) 如果一个抽象类中的所有方法都是抽象的,可以采用另一种方式——“接口”来定义。接口的概念接口是抽象方法和常量值的定义的集合。从本质上讲,接口是一种特殊的抽象类,这种抽象类中只包含常量和方法的定义,而没有方法的实现。从语法上看,接口是一种与“类”很相似的结构,只是接口中的所有方法都是抽象的,只有声明、没有方法体。接口声明的关键字是interface。47目前四十七页\总数六十四页\编于十四点什么是接口?认识一下接口◎接口特性:接口不可以被实例化实现类必须实现接口的所有方法实现类可以实现多个接口接口中的变量都是静态常量publicinterfaceMyInterface

{publicvoidfoo();//其他方法}所有方法都是:publicabstract抽象类除外Java中的多继承常作为类型使用目前四十八页\总数六十四页\编于十四点接口的声明格式:[权限修饰符]interface接口名

[extends父接口列表]{ //抽象方法和静态常量}例如:publicinterfaceRunner{ intid=1; publicvoidstart(); publicvoidrun(); publicvoidstop(); }49目前四十九页\总数六十四页\编于十四点说明:接口的修饰符可以是public或缺省;接口中的方法都是抽象的和公有(public)的,仅有方法说明,没有方法体;接口中的常量默认是公共的、静态的和最终的,在声明时一般不需要用public、static、final。接口关心的是“做什么”,不关心“怎样做”,即是声明一种规范,而不是实现;生活中类似的例子:电脑主板中的各种插槽等;通过接口可以间接实现多重继承。50目前五十页\总数六十四页\编于十四点接口的实现 接口规定了类的“原型”,具体实现由实现该接口的类来完成,格式如下:[修饰符]class类名[extends父类][implements接口1,接口2,…]{ …… //包含对接口的所有方法的实现}//例子publicclassPersonimplementsRunner{

publicvoidstart(){

//准备工作:弯腰、蹬腿、咬牙、瞪眼

//开跑

}

publicvoidrun(){ //摆动手臂 //维持直线方向

} publicvoidstop(){ //减速直至停止、喝水。

}}51目前五十一页\总数六十四页\编于十四点说明:一个类可以实现多个接口,从而达到多重继承的目的;多个无关的类可以实现同一个接口;通过接口可以实现不相关类的相同行为,而不需要考虑这些类之间的层次关系;一个具体类实现接口时,必须实现接口中的所有抽象方法;当一个类未实现接口中的所有抽象方法时,应声明为抽象类;类在实现某个接口的抽象方法时,必须使用完全相同的方法头,例如:接口定义中通常省略public修饰符,但在实现抽象方法时必须显式使用public修饰符;通过接口可以指明多个类需要实现的方法;与继承关系类似,接口与实现类之间存在多态性。???52目前五十二页\总数六十四页\编于十四点下面类A的定义形式中,哪一个是正确的?(1)classAextendsB,C{ ……}(2)classAimplementsB,C{ ……}(3)classAextendsBimplementsC{ ……}(4)classAextendsBimplementsC,D{ ……}答案:(2)、(3)、(4)53目前五十三页\总数六十四页\编于十四点通过接口可以实现不相关类的相同行为<<interface>>Runner+start()+run()+stop()Person+start()+run()+stop()+dance()Car+start()+run()+stop()+fillFuel()+crack()Bird+start()+run()+stop()+fly()54目前五十四页\总数六十四页\编于十四点//接口应用例子interfaceRunner{ //接口1 publicvoidrun();}interfaceSwimmer{ //接口2 publicvoidswim();}abstractclassAnimal{ //抽象类,去掉关键字abstract是否可行? publicabstractvoideat();}classPersonextendsAnimalimplementsRunner,Swimmer{//继承类,实现接口 publicvoidrun(){ System.out.println("我是飞毛腿,跑步速度极快!"); } publicvoidswim(){ System.out.println("我游泳技术很好,会蛙泳、自由泳、仰泳、蝶泳..."); } publicvoideat(){ System.out.println("我牙好胃好,吃啥都香!"); }}55目前五十五页\总数六十四页\编于十四点publicclassInterfaceTest{ publicstaticvoidmain(Stringargs[]){ InterfaceTestt=newInterfaceTest();

Personp=newPerson(); t.m1(p);

//接口回调,下同

t.m2(p); t.m3(p); } publicvoidm1(Runnerr){r.run();} //接口作参数,下同 public

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论