继承是面向对象编程最重要的优点之一。它是如此重要,以至于您为了最高效地利用继承的特点,就必须正确理解继承的概念。继承包括以下一些主要概念:
extends 关键字: 继承是在对类进行声明时定义的。您可以使用 extends 关键字来指定您正在编写的类的超类。
构造函数:在子类中并不能继承构造函数,但是您通常可以在子类的构造函数中调用超类的构造函数。
重载/覆盖: 重载是指编写多个名字相同但是参数不同的方法。 覆盖是指在子类中修改所继承的方法的实现。
Object 类: 所有的 Java 对象最终都是从 Object 类继承来的, Object 类定义了每个 Java 对象具有的所有基本功能。
接口: 接口是对行为的描述,但是并不提供实现。
扩展类
在 Visual Basic 中,一个类不能继承其他类,但是 Java 语言允许单继承。继承是一种代码重用方法。如果类 A 继承了类 B(或者说类 A 对类 B 进行了扩展),那么类 A 就自动继承了类 B 中的所有 public 和 protected 类型的成员。如果类 A 与类 B 在同一个包中,那么类 A 还会继承所有具有默认(或 包)访问权限的成员。但是有一点非常重要,需要提醒大家注意,子类永远不会继承它们所扩展的超类的的私有成员。
当您对一个类进行扩展之后,就可以在新类中添加用来定义与超类中不同的属性和操作的新域和新方法了。而且,您也可以 覆盖子类中那些与超类行为不同的操作。
在定义类时,您可以显式地对一个类进行扩展。要扩展一个类,您只需要子类名后面简单地跟上 extends 关键字及要扩展的类名即可。如果您没有显式地对一个类进行扩展,那么 Java 编译器就会自动对 Object 类进行扩展。这样,所有的 Java 对象最终都是 Object 类的一个子类。
扩展的例子
让我们假设您想创建一个新的 CheckingAccount 类。 CheckingAccount 是一种特殊的 BankAccount 。换而言之, CheckingAccount 与 BankAccount 具有相同的属性和操作。然而, CheckingAccount 多了一个操作——存入现金。因此您可以定义 CheckingAccount 类,使其对 BankAccount 进行扩展,并添加一个 cashCheck() 方法,如清单 14 所示。
清单 14. 扩展类
2
3 public void cashCheck(float amount) {
4
5 withdraw(amount);
6
7 }
8
9 }
10
11
子类的构造函数
构造函数实际上并不是类的成员,构造函数也不会被子类继承。 BankAccount 构造函数创建的是 BankAccount 对象,因此您不能在 CheckingAccount 类中使用它来创建 CheckingAccount 对象。然而,您可以使用超类的构造函数作为子类的一部分使用。换而言之,您通常需要在子类的构造函数中调用超类的构造函数,从而对子类的对象进行部分初始化。您可以使用 super 关键字实现这种功能,后面跟上一串参数,表示您要调用的超类的构造函数的参数。如果您正在一个构造函数中使用 super 关键字来调用超类的构造函数,那么它就必须作为构造函数体的第一条语句出现。
例如,假设您要创建一个 CheckingAccount 构造函数来对 CheckingAccount 对象进行初始化。您希望创建的 CheckingAccount 对象都有 balance 初始值,因此您要传递一个美元数量作为参数。这与 BankAccount 类中的构造函数完全相同,因此您想使用构造函数来为您实现这种功能,如清单 15 所示。
清单 15. 子类的构造函数
2
3 public CheckingAccount(float balance) {
4
5 super(balance);
6
7 }
8
9 public void cashCheck(float amount) {
10
11 withdraw(amount);
12
13 }
14
15 }
16
17
您也可以在子类中使用 super 关键字来显式地引用超类的成员。
重载和覆盖
Java 语言允许您定义多个同名的方法,前提是这些方法采用的参数不同。例如,清单 16 定义了第二个 cashCheck() 方法,这个方法使用要存入的支票数量和使用的费用作为参数。这称为方法 重载(overloading)。
清单 16. 方法重载
2
3 withdraw(amount);
4
5 }
6
7 public void cashCheck(float amount, float fee) {
8
9 withdraw(amount+fee);
10
11 }
12
13
当您创建一个子类时,通常都希望 重载 从超类中继承的方法的行为。例如,让我们假设 CheckingAccount 和 BankAccount 之间的区别是您从 CheckingAccount 帐号中提款时要收取一定的费用。在 CheckingAccount 类中,您需要对 withdraw() 进行重载,以便多扣取 $0.25 的费用。您可以定义 CheckingAccount withdraw() 方法,在这个方法中使用 super 关键字调用 BankingAccount 的 withdraw() 方法,如清单 17 所示。
清单 17. 方法覆盖
2
3 super.withdraw(amount+0.25F);
4
5 }
6
7
Object 类
Object 类是 Java 类层次结构中的一个非常特殊的类。所有的 Java 类最终都是 Object 类的一个子类。换而言之,Java 语言支持一种具有一个中心根类的层次结构,而 Object 类就是这个类层次的根类。在 Visual Basic 中也有类似的概念: Object 变量可以被实例化为任何类的对象。
由于所有的 Java 对象都是从 Object 类继承来的,因此您可以对任何 Java 对象都调用在 Object 类中定义的方法,而且每个对象的行为都类似。例如, Object 类定义了一个 toString() 方法,该方法会返回一个代表该对象的 String 对象。您可以对任何 Java 对象调用 toString() 方法,并期望得到该对象的一个字符串表示。大部分定义都会覆盖 toString() 方法,这样就可以返回一个表示这个特殊类的一个特殊的字符串。
让 Object 位于 Java 类层次的根位置的另一种含义是,所有对象都可以强制类型转换为 Object 对象。在 Java 语言中,您可以定义具有 Object 类对象的数据结构,这些数据结构中可以存放任何 Java 对象。
接口
我们已经提到一个 Java 类只允许单继承,这就是说一个 Java 类只能对一个类进行扩展。Java 语言的设计者认为多继承太过复杂,因此就决定不支持多继承,而是支持 接口。 接口类似于一个不能实例化的类,其中有方法的定义,但是没有真正实现。
您可以像类一样定义接口,不同之处是要使用 interface 关键字,而不是使用 class 关键字。一个接口可以对任意多个超级接口进行扩展。接口中的方法不能包括实现。接口方法只是一些简单的方法定义;不能有任何方法函数体。这与 Visual Basic 中使用方法的概念类似;它们只包括属性和方法定义,但是没有任何代码。
Account 接口
清单 18 中所列出的代码显示了如何编写一个基本的 Account 接口,该接口为银行帐号定义了一组基本的功能。注意您在接口中声明的这些方法没有函数体。
清单 18. Account 接口
2
3 public static final float INTEREST = 0.35F;
4
5 public void withdraw(float amount);
6
7 public void deposit(float amount);
8
9 }
10
11
接口实现
一个 Java 类只能对一个类进行扩展,但是却可以 实现任意多个接口。当一个类实现一个接口时,必须实现该接口中定义的所有方法。
清单 19 定义了一个 SavingsAccount 类,它实现了 Account 接口。由于 Account 接口定义了两个方法: withdraw(float amount) 和 deposit(float amount) ,因此 SavingsAccount 类必须对这两个方法都提供一个实现。 SavingsAccount 类仍然可以扩展其他类,也可以实现其他任何接口,前提是这些接口不能定义与 Account 接口相同的成员。
清单 19. 接口实现
2
3 private float balance;
4
5 public SavingsAccount(float balance) {
6
7 this.balance = balance;
8
9 }
10
11 public void cashCheck(float amount, float fee) {
12
13 withdraw(amount+fee);
14
15 }
16
17 public void withdraw(float amount) {
18
19 balance += balance;
20
21 }
22
23 public void deposit(float amount) {
24
25 balance -= balance;
26
27 }
28
29 }
30
31
回顾
到目前为止,您应该已经掌握了 Java 语言的基本组件,并且能够熟练编写简单的 Java 程序。特别是,您应该能够:
编写一个具有 main() 方法的 Java 类,编译并运行它。
编写一个 Java 接口并编译它。
为您的类编写一个或多个构造函数。
编写一个扩展另一个类的类,并实现一个或多个接口。
创建并应用使用了新关键字和构造函数的调用。
您还应该足够自信地开始探究更高级的 Java 代码。一个很好的起点就是 Java 平台类本身。获得 Java 语言使用经验的非常好的途径是浏览 API 文档,并开始使用那些类来编写程序。此外,也请参阅侧栏 磨练您的技巧以获得补充本文的一些精选资源。