
3.1.4 使用多个构造函数
大多数情况下可以用多种方式创建对象。为了适应这种情况,你需要提供多个构造函数。例如,请看Count类:

一方面,我们可以初始化属性count为0,实现这一点很简单,即可以在一个构造函数中初始化count为0,如下所示:

另一方面,我们可以传递一个初始化参数,从而可以设置count为其他数字:

这叫作重载方法(重载适用于所有方法,不只是构造函数)。大部分的面向对象语言都提供了重载方法的功能。
重载方法
重载可以让程序员重复使用相同的方法名,只要每次方法签名不同即可。方法签名包含了方法名以及参数列表(如图3.1所示)。

图3.1 签名的组成
所以,以下所有方法均拥有不同的签名:

签名
方法签名可能包含返回值类型,也可能不包含返回值类型,这取决于不同的语言。在Java和C#中,返回值类型并不属于签名的一部分。例如,以下代码即使返回值类型不同,也不能通过编译:

了解签名的最好方式是编写一些代码然后进行编译。
通过使用不同的签名,你可以根据不同的构造函数来构造对象。如果你不能保证每次都能掌握足够的信息,那么很适合这种方式。例如,当创建一个购物车时,顾客可能已经登录了自己的账号(你会得到顾客的所有信息)。而一个全新的顾客可能会向购物车中放入产品,但没有任何账号信息,这两种情况下构造函数的初始化方式是不同的。
使用UML对类建模
我们再回头看第2章中用到的数据库阅读器例子。构造数据库阅读器有两种方式:
·传入数据库名称和光标在数据库中的起始位置
·传入数据库名称和光标在数据库中的期望位置
图3.2展示了DataBaseReader类的类图。注意图中列出了此类的两个构造函数。尽管该图显示了两个构造函数,但并未包含参数列表,所以无法区分出这两个构造函数。为了区分这两个构造函数,可以查看下面列出的DataBaseReader类的对应代码。

图3.2 DataBaseReader类图
无返回值类型
注意在该类图中,构造函数没有返回值类型。除了构造函数之外,其他所有方法必须要有返回值类型。
以下代码片段展示了该类的构造函数,以及构造函数如何初始化属性(参见图3.3):

图3.3 创建新对象

请注意在两个例子中如何初始化startPosition。如果构造函数没有通过参数列表传递信息,那么startPostion会被初始化为默认值,即0。
如何构造父类
当使用继承时,你必须知道如何构造父类。请记住当使用继承时,也继承了父类的所有东西,因此必须熟悉父类的数据和行为。任何继承的属性都是完全可见的。然而对构造函数的继承则是不可见的。如果遇到了new关键字,那么会分配对象,并发生以下步骤(参见图3.4):
1.在构造函数中会调用父类的构造函数。如果没有显式调用父类的构造函数,那么系统会默认自动调用。不过可以在字节码中看到这段代码。
2.对象中的所有属性都会被初始化。这些属性是类定义中的属性(实例变量),不是构造函数或其他方法中的属性(局部变量)。在DataBaseReader代码中,整数startPosition是类的实例属性。
3.执行构造函数中的其余代码。

图3.4 构造对象