第5章〓抽象类与接口内容导览学习目标 ●能够根据项目设计需求设计抽象类 ●能够学会定义接口,应用类实现接口 ●理解接口与抽象类的区别,能够使用接口和抽象类解决工程问题 ●掌握集合及集合接口的使用方法,学会使用集合实现对象的增删改查操作 5.1引例 例5.1设计一款电子游戏,游戏中有不同类型怪物,如英雄、火龙、天使、僵尸等。这些角色既有共同的行为(如战斗),也有不同行为(如英雄具有战斗、游泳、飞行等功能)。请试着设计游戏,让系统足够灵活,易于扩展,如游戏升级时能方便地增加新的角色;同时有利于编程,能够让多个人一起协同开发。Java面向对象程序设计(第3版)第5章抽象类与接口分析: 通过第4章中继承的学习,我们可以将战斗的行为抽象为父类的方法,通过继承使子类都具有战斗的行为。但考虑到角色可能具有多个功能,我们可以利用接口的多继承机制,将其他功能定义为接口,在接口中定义抽象方法。在角色设计时,游泳、飞行设计为单独的接口,每个角色根据设计要求通过多继承实现,如设计一个英雄的角色,具有3个功能。//文件名为Jpro5_1.java 1 interface CanSwim{ 2 void swim(); 3 } 4 interface CanFly{ 5 void fly(); 6 } 7class ActionCharacter{ 8 public void fight(){ 9System.out.println("can fight!"); 10 } 11} 12class Hero extends ActionCharacter implements CanSwim,CanFly{ 13public void swim(){ 14 System.out.println("can swim!"); 15} 16public void fly(){ 17System.out.println("can fly!"); 18} 19} 20public class Jpro5_1{ 21public static void u(CanSwim x){ 22x.swim(); 23} 24public static void v(CanFly x){ 25x.fly(); 26} 27public static void w(ActionCharacter x){ 28x.fight(); 29} 30public static void main(String args[]){ 31Hero h=new Hero(); 32u(h); 33v(h); 34w(h); 35} 36}程序运行结果为:can swim! can fly! can fight!程序分析: 在上述Java源程序Jpro5_1.java中定义了两个接口和一个类。第1行定义接口CanSwim,其定义了抽象方法swim();第4行定义接口CanFly,其定义了抽象方法fly();第7行定义类ActionCharacter,第12行定义Hero类从ActionCharacter类扩展,利用implements将CanSwim和CanFly接口合并。在Jpro5_1类中有3个方法: u()、v()和w(),它们接受不同接口/类参数。一旦Hero对象生成,可被传送到这3个方法中的任意一个。 在解决这个问题时,我们提到了抽象方法、接口等,下面将一一介绍。 5.25.2抽象类 在面向对象程序设计中,父类抽取并定义了其子类共同拥有的属性和方法。在这些属性和方法中,有些是已经明确并可以在父类中实现的,有些则与具体的子类有关且无法在父类中实现。对于无法确定的方法,我们可以将其在父类中定义为抽象方法,相应地该父类也被定义为抽象类。例如,在学生成绩管理系统中,用户有三个属性: id(可用作登录用户名)、password(密码)、name(姓名);有一个登录方法: boolean login(String id,String password)。系统中设有管理员类、教师类和学生类三类用户,可以继承用户类的3个属性并重写登录方法。此时,用户类的登录方法可以定义为抽象方法,该用户类也应该定义为抽象类。 抽象类的定义与一般类一样,都有数据和方法,定义格式与一般类也非常类似,只是在定义类的class前增加一个关键字abstract来表示定义一个抽象类,即用abstract修饰的类称为抽象类。 抽象方法是抽象类中的一种特殊方法,用abstract关键字来修饰。在抽象类中,抽象方法仅有方法头,而没有方法体,它的方法体放在子类中,因此抽象方法必须在子类中重写,否则没有意义。含有抽象方法的类一定是抽象类,抽象类中除了抽象方法,还可以包括其他普通的成员方法。 抽象类和抽象方法的声明格式如下:abstract class 类名{ 成员变量; 成员方法(){方法体} abstract成员方法(); }例如,定义一个抽象类User。public abstract class User{ private String id; private String name; private String password; public abstract boolean login(String id,String password); }抽象类不能创建对象,它只能作为其他类的父类,它的存在仅是为了继承而用。User类是抽象类,不能用new创建它的实例,但它可以被继承。抽象方法login()只有方法声明部分和“空”实现,它的具体实现由其子类完成。例如,第7章介绍的InputStream类和OutputStream类都属于抽象类,均包含抽象方法和其他方法。 注意: 如果一个类没有显式地被abstract修饰,但是类体中包含抽象方法,则该类也为抽象类。 例5.2下面定义了一个抽象类,然后通过继承实现该抽象类。//文件名为Jpro5_2.java 1 abstract class Animal{//抽象类 2 String name; 3 public abstract void go();//抽象方法 4 } 5 class Cat extends Animal{ 6 public Cat(String name){ 7 this.name=name; 8 } 9 public void go(){//方法的覆盖 10System.out.println(name+" can run."); 11} 12} 13class Bird extends Animal{ 14Bird(String name){ 15this.name=name; 16} 17public void go(){//方法的覆盖 18System.out.println(name+" can fly."); 19} 20} 21public class Jpro5_2{ 22public static void main(String args[]){ 23Cat c=new Cat("Cady"); 24Bird b=new Bird("Bird"); 25c.go(); 26b.go(); 27} 28}程序分析: 程序首先定义了一个抽象类Animal,该抽象类包含一个成员变量和一个抽象方法。随后定义了两个类Cat和Bird,它们都继承了抽象类Animal。在主方法main()中定义了一个Cat对象和一个Bird对象,并且通过对象调用相应的go()方法。 【练习5.1】 1. [单选题]下列关于抽象类的描述,错误的是() 。 A. 抽象类中有抽象方法B. 用abstract修饰的类是抽象类 C. 抽象方法没有方法体D. 抽象类可以用来实例化对象 2. [单选题]下列关于抽象类定义,正确的是()。 A. abstract AbstractClass{ abstract void method(); } B. class abstract AbstractClass{ abstract void method(); } C. abstract class AbstractClass{ abstract void method(); } D. abstract class AbstractClass{ abstract void method(){ System.out.println(“method”); } } 3. [程序填空]请在程序的每条横线处填写一个语句,使程序能实现功能。①class Vehicle{ abstractvoid go();//抽象方法 } class Car ② Vehicle{ //继承抽象类 public void go(){ //方法的重写 System.out.println("小汽车启动"); } } public class Main{ public static void main(String[] args){ Car c=new Car();//创建一个Car对象 c.go(); } }4. [单选题]下列程序的运行结果是()。abstract class MineBase{ abstract void amethod(); static int i; } public class Mine extends MineBase{ public static void main(String argv[]){ int[] ar=new int[5]; for (i=0; isearchAll(); 10//根据学号查询学生 11Student findStudentById(String studentId); 12}上面的程序段定义了一个名为StudentDao的接口,其中有五个抽象方法: add()、delete()、update()、searchAll()和findStudentById(),分别用于学生信息的添加、删除、修改、查找全部学生、按学号查找学生。 与类一样,接口也具有继承性。定义接口时可以使用extends关键字定义该新接口是某个已经存在的父接口的派生接口,它将继承父接口的所有属性和方法。与类的单继承不同,一个接口可以有多个父接口,接口名称之间用“,”分隔。新的接口将继承所有父接口的属性和方法。 5.3.25.3.2接口实现 接口中只是声明了提供的功能和服务,而功能和服务的具体实现需要在实现接口的类中定义。在类中实现接口的格式如下:[类修饰符] class 类名 [extends 父类名] [implements 接口名列表]其中,接口名列表包括多个接口名称,各接口间用逗号分隔。implements是实现接口的关键字。实现接口的类如果不是抽象类,就必须实现接口中定义的所有方法并给出具体的实现代码,当然还可以使用接口中定义的任何常量。 例5.4接口的实现示例。//文件名为Jpro5_4.java 1 interface Shape{//定义接口Shape 2 double PI=3.14; 3 void print(); 4 } 5 class Circle implements Shape{//实现接口Shape 6 public void print(){ 7 System.out.println("我实现了接口"+PI); 8 } 9 } 10public class Jpro5_4{ 11public static void main(String args[]){ 12Circle circle=new Circle(); 13circle.print(); 14} 15}请读者自行运行结果。 程序分析: 程序中定义了一个接口Shape,其包含一个常量PI和方法print(),然后定义了一个类Circle实现接口Shape。注意在实现方法print()时,其修饰符必须为public。在main()方法中创建了一个Circle类对象circle,然后通过circle调用方法print()。 在学生成绩管理系统中,接口StudentDao将由StudentDaoImpl来实现,其实现语句为public class StudentDaoImpl implements StudentDao具体实现方法详见第10章。 实现接口时,需要注意以下问题: ●如果实现接口的类不是abstract修饰的抽象类,那么在类的定义部分必须实现接口中定义的所有方法并给出具体的实现代码,这是因为非抽象类中不可以存在抽象方法。 ●如果实现接口的类是abstract修饰的抽象类,那么它可以不实现该接口的所有抽象方法。 ●在实现接口方法时,必须将方法声明为公共方法,而且还要求方法的参数列表、名称和返回值与接口中定义的完全一致。 ●如果在实现接口的类中所实现的方法与抽象方法有相同的方法名称和不同的参数列表,则只是重载一个新的方法,并没有实现接口中的抽象方法。 ●如果接口的抽象方法的访问修饰符规定为public,则类在实现这些抽象方法时,必须显式地使用public修饰符,否则系统会提示出错警告。 ●如果接口中的方法的返回类型不是void,则在类中实现该方法时,方法体中至少要有一条return语句。 5.3.35.3.3抽象类与接口的区别 Java中的抽象类和接口有很多相似之处,都含有抽象方法,抽象方法的实现都放在其他类中实现。但两者却是两种完全不同的类型,它们之间的主要区别如表51所示。表51抽象类与接口的区别 比较项目抽象类接口方法及实现包含未实现的抽象方法,也可以包含已给出具体实现的方法接口是完全抽象的,所有方法均不需要给出具体的实现形式继承与实现子类通过extends关键字来继承抽象类。若子类不是抽象类,其需要实现抽象类中所有的抽象方法子类使用implements关键字实现接口,且需要实现接口中声明的所有方法构造器抽象类可以有构造器接口不能有构造器与普通Java类的区别除了不能被实例化之外,关键字和普通Java类没有任何区别接口是完全不同的类型访问修饰符抽象方法可以由public、protected和default进行修饰接口中方法的默认修饰符是public,通常不使用其他修饰符多继承一个Java类只能继承一个抽象类一个Java类能实现多个接口扩展新方法在抽象类中添加新方法时,可以给出该方法的默认实现,故不需要修改其他代码若往接口中添加新方法,必须改变实现该接口的其他所有类在一般的应用程序设计中,往往将抽象类和接口结合起来应用,这样代码结构更加清晰,容易扩展。采用何种技术要根据应用场景来决定,通常可以遵循的规则如下: ●定义接口。接口是系统的核心,定义了要完成的功能,包含主要的方法声明,因此系统最顶层采用接口。 ●定义抽象类。如果某些类实现的方法有相似性,则可以抽象出一个抽象类包含方法声明;如果顶层接口有共同部分要实现,则定义抽象类实现接口。 ●由抽象类的具体类各自实现个性化的方法。 Java API中的集合框架很好地体现了这种设计原则,我们将在5.4节中详细讲解它。 【练习5.2】 1. [单选题]下列关于接口的描述,错误的是()。