JAVA 编 程 技 术 主编 贾振华 2010年1月
第4章 JAVA的继承与接口
如果类B具有类A的全部属性和方法,而且又具有自己特有的某些属性和方法,则把类A称作一般类,把类B叫做类A的特殊类。 JAVA 继 承 的 概 念 如果类B具有类A的全部属性和方法,而且又具有自己特有的某些属性和方法,则把类A称作一般类,把类B叫做类A的特殊类。 特殊类却自动地、隐含地拥有它的一般类(以及所有更上层的一般类)中定义的属性和操作。特殊类的对象拥有其一般类的全部或部分属性与方法,称作特殊类对一般类的继承。 轮船具有吨位、时速、吃水线等属性,并具有行驶、停泊等服务;客轮具有轮船的全部属性与服务,又有自己的特殊属性(如载客量)和服务(如供餐等)。若把轮船看做一般类,则客轮是轮船的特殊类。
继承所表达的就是一种对象类之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法。 JAVA 继 承 的 概 念 继承所表达的就是一种对象类之间的相交关系,它使得某类对象可以继承另外一类对象的数据成员和成员方法。 若类B继承类A时,则属于B的对象便具有类A的全部或部分性质(数据属性)和功能(操作)我们称被继承的类A为基类、父类或超类,而称继承类B为A的派生类或子类。父类与子类的层次关系如图所示。
JAVA 继 承 的 概 念 图 父类与子类的层次关系
继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。 提供软件复用功能。 JAVA 继 承 的 特 征 继承关系是传递的。 继承简化了人们对事物的认识和描述,能清晰体现相关类间的层次结构关系。 提供软件复用功能。 通过增强一致性来减少模块间的接口和界面大大增加程序的易维护性。 提供多重继承机制(非直接提供)。
JAVA 继 承 的 特 征 图 单重继承与多重继承的例子
由继承而得到的类称为子类,被继承的类称为父类(超类)。 声明一个类的子类的格式如下: class 子类名 extends 父类名 { … } JAVA 父 类 与 子 类 由继承而得到的类称为子类,被继承的类称为父类(超类)。 声明一个类的子类的格式如下: class 子类名 extends 父类名 { … } 如果一个类的声明中没有使用extends关键字,是否存在继承关系? Java.lang.Object
JAVA 子类和父类在同一包中的继承性 如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是private的方法作为自己的方法,继承的成员变量或方法的访问权限保持不变。
JAVA 子类和父类不在同一包中的继承性 如果子类和父类不在同一个包中,那么,子类继承了父类的protected、public成员变量做为子类的成员变量,并且继承了父类的protected、public方法为子类的方法,继承的成员或方法的访问权限保持不变。
JAVA 子 类 对 象 的 构 造 过 程 用子类创建对象时,不仅子类中声明的成员变量被分配了内存,而且父类的成员变量也都分配了内存空间,但只将其中一部分(子类继承的那部分)作为分配给子类对象的变量。
JAVA 成 员 变 量 的 隐 藏 对于子类可以从父类继承的成员变量,只要子类中声明的成员变量和父类中的成员变量同名时,子类就隐藏了继承的成员变量,子类自己声明定义的方法操作与父类同名的成员变量是指子类重新声明定义的这个成员变量。
子类可以隐藏从父类继承的成员变量和方法,如果在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。 JAVA super 关 键 字 子类可以隐藏从父类继承的成员变量和方法,如果在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。
如果在子类的构造方法中,没有明显地写出super关键字来调用父类的构造方法,默认有super(); JAVA 使用 super 关键字调用父类构造方法 子类不继承父类的构造方法,因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字super来表示,而且super必须是子类构造方法中的头一条语句。 如果在子类的构造方法中,没有明显地写出super关键字来调用父类的构造方法,默认有super();
在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。 JAVA 使用 super 操作被隐藏的成员变量和方法 在子类中想使用被子类隐藏的成员变量或方法就可以使用关键字super。 比如super.x、super.play()就是访问和调用被子类隐藏的成员变量x和方法play()。
假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,比如: JAVA 对 象 的 上 转 型 对 象 假设,A类是B类的父类,当用子类创建一个对象,并把这个对象的引用放到父类的对象中时,比如: A a; a = new B(); 或 B b = new B(); a = b; 这时,称对象a是对象b的上转型对象。
JAVA 对 象 的 上 转 型 对 象
不要将父类创建的对象和子类对象的上转型对象混淆。 可以将对象的上转型对象再强制转换到一个子类对象。 JAVA 对 象 的 上 转 型 对 象 不要将父类创建的对象和子类对象的上转型对象混淆。 可以将对象的上转型对象再强制转换到一个子类对象。 不可以将父类创建的对象的引用赋值给子类声明的对象。
用关键字abstract修饰的类称为abstract类(抽象类)。如: abstract class A { … } JAVA abstract 类 和 abstract 方 法 用关键字abstract修饰的类称为abstract类(抽象类)。如: abstract class A { … } 用关键字abstract修饰的方法称为abstract方法(抽象方法),例如: abstract int min(int x,int y);
JAVA abstract 类 假设我们要编写一个计算矩形、三角形和圆的面积与周长的程序,若按前面所学的方式编程,我们必须定义四个类:圆类、三角形类、矩形类和使用前三个类的公共类,它们之间没有继承关系,如图所示。程序写好后虽然能执行,但从程序的整体结构上看,三个类之间的许多共同属性和操作在程序中没有很好地被利用,致使重复编写代码,降低了程序的开发效率,且使出现错误的机会增加。
JAVA abstract 类 图 具有相同特征却彼此独立的几个类
JAVA abstract 类 图 抽象类及其应用
(1) 凡是用abstract 修饰的类被称为抽象类。凡是 用abstract修饰的成员方法被称为抽象方法。 JAVA abstract 类 抽象类是它的所有子类的公共属性的集合,是包含一个或多个抽象方法的类。使用抽象类的一大优点就是可以充分利用这些公共属性来提高开发和维护程序的效率。 对于抽象类与抽象方法的限制如下: (1) 凡是用abstract 修饰的类被称为抽象类。凡是 用abstract修饰的成员方法被称为抽象方法。 (2) 抽象类中可以有零个或多个抽象方法,也可以 包含非抽象的方法。 (3) 抽象类中可以没有抽象方法,但是,有抽象方 法的类必须是抽象类。
(4) 对于抽象方法来说,在抽象类中只指定其 方法名及其类型,而不书写其实现代码。 (5) 抽象类可以派生子类,在抽象类派生的子 JAVA abstract 类 (4) 对于抽象方法来说,在抽象类中只指定其 方法名及其类型,而不书写其实现代码。 (5) 抽象类可以派生子类,在抽象类派生的子 类中必须实现抽象类中定义的所有抽象方 法。 (6) 抽象类不能创建对象,创建对象的工作由 抽象类派生的子类来实现。 (7) 如果父类中已有同名的abstract方法,则子 类中就不能再有同名的抽象方法。
(8) abstract 不能与 final 并列修饰同一个类。 JAVA abstract 类 (8) abstract 不能与 final 并列修饰同一个类。 (9) abstract 不能与 private、static、final并 列修饰同一个方法。
abstract类只关心操作,但不关心这些操作具体实现的细节,可以使程序的设计者把主要精力放在程序的设计上,而不必拘泥于细节的实现上。 JAVA abstract 类 与 多 态 abstract类只关心操作,但不关心这些操作具体实现的细节,可以使程序的设计者把主要精力放在程序的设计上,而不必拘泥于细节的实现上。 使用多态进行程序设计的核心技术之一是使用上转型对象,即将abstract类声明对象作为其子类的上转型对象,那么这个上转型对象就可以调用子类重写的方法。
JAVA abstract 类 与 多 态
一个类通过使用关键字implements声明自己实现一个或多个接口。 JAVA 什 么 是 接 口? 为了克服Java单继承的缺点,Java使用了接口,一个类可以实现多个接口。 使用关键字interface来定义一个接口。 interface 接口的名字 接口体 接口体中包含常量定义和方法定义两部分。 接口的使用 一个类通过使用关键字implements声明自己实现一个或多个接口。
接口定义用关键字interface,而不是用class。 接口中定义的数据成员全是final,即常量。 JAVA 定 义 接 口 的 注 意 事 项 接口定义用关键字interface,而不是用class。 接口中定义的数据成员全是final,即常量。 接口中没有自身的构造方法,所有成员方法都是抽象方法。 接口也具有继承性,可以通过extends关键字声明该接口的父接口。
在类中,用implements关键字就可以调用接口。 JAVA 类 实 现 接 口 的 注 意 事 项 在类中,用implements关键字就可以调用接口。 如果实现某接口的类不是abstract的抽象类,则在类的定义部分必须实现指定接口的所有抽象方法。 接口的抽象方法的访问限制符都己指定为public,所以类在实现方法时,必须显式地使用public修饰符。 如果实现某接口的类是abstract的抽象类,则它可以不实现该接口所有的方法。
接口可以增加很多类都需要具有的功能,不同的类可以实现相同的接口,同一个类也可以实现多个接口。 JAVA 理 解 接 口 接口是顶层设计。 接口可以增加很多类都需要具有的功能,不同的类可以实现相同的接口,同一个类也可以实现多个接口。 接口只关心操作,并不关心操作的具体实现。 接口的思想在于它可以增加很多类都需要具有的功能,而且实现相同的接口类不一定有继承关系。
JAVA 回 调 函 数 编程分为两类:系统编程(system programming)和应用编程(application programming)。所谓系统编程,简单来说,就是编写库;而应用编程就是利用写好的各种库来编写具某种功用的程序,也就是应用。系统程序员会给自己写的库留下一些接口,即API(application programming interface,应用编程接口),以供应用程序员使用。所以在抽象层的图示里,库位于应用的底下。
JAVA 回 调 函 数 当程序跑起来时,一般情况下,应用程序(application program)会时常通过API调用库里所预先备好的函数。但是有些库函数(library function)却要求应用先传给它一个函数,好在合适的时候调用,以完成目标任务。这个被传入的、后又被调用的函数就称为回调函数(callback function)。
JAVA 回 调 函 数 打个比方,有一家旅馆提供叫醒服务,但是要求旅客自己决定叫醒的方法。可以是打客房电话,也可以是派服务员去敲门,睡得死怕耽误事的,还可以要求往自己头上浇盆水。这里,“叫醒”这个行为是旅馆提供的,相当于库函数,但是叫醒的方式是由旅客决定并告诉旅馆的,也就是回调函数。而旅客告诉旅馆怎么叫醒自己的动作,也就是把回调函数传入库函数的动作,称为登记回调函数(to register a callback function)
JAVA 回 调 函 数 假如你到一个商店买东西,刚好你要的东西没有货,于是你在店员那里留下了你的电话,过了几天店里有货了,店员就打了你的电话,然后你接到电话后就到店里去取了货。在这个例子里,你的电话号码(或者留微信,留QQ)就叫回调函数,你把电话留给店员就叫登记回调函数,店里后来有货了叫做触发了回调关联的事件,店员给你打电话叫做调用回调函数,你到店里去取货叫做响应回调事件。
JAVA 回 调 函 数 回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。
JAVA 接 口 回 调 接口回调:可以把使用某一接口的类创建的对象的引用赋给该接口声明的接口变量,那么该接口变量就可以调用被类实现的接口的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法这一过程称为对象功能的接口回调。 如下例所示:定义一个接口 interface People{ void peopleList(); }
JAVA 接 口 回 调 class Student implements People{ public void peopleList(){ System.out.println("I’m a student."); } class Teacher implements People{ System.out.println("I’m a teacher.");
JAVA 接 口 回 调 public class Example{ public static void main(String args[ ]){ People a; //声明接口变量 a=new Student(); //实例化,接口变量中存放对象的引用 a.peopleList(); //接口回调 a=new Teacher(); //实例化,接口变量中存放对象的引用 } 结果: I’m a student. I’m a teacher.
可以通过在接口中声明若干个abstract方法,表明这些方法的重要性,方法体的内容细节由实现接口的类去完成。 JAVA 接 口 与 多 态 可以通过在接口中声明若干个abstract方法,表明这些方法的重要性,方法体的内容细节由实现接口的类去完成。 使用接口进行程序设计的核心思想是使用接口回调,即接口变量存放实现该接口的类的对象的引用,从而接口变量就可以回调类实现的接口方法。
JAVA 接 口 与 多 态
abstract类和接口都可以有abstract方法。 接口中只可以有常量,不能有变量;而abstract类中即可以有常量也可以有变量。 JAVA abstract类和接口比较 abstract类和接口都可以有abstract方法。 接口中只可以有常量,不能有变量;而abstract类中即可以有常量也可以有变量。 abstract类中也可以有非abstract方法,接口不可以。