
3.2 方法的特殊用法
类中的方法分为用于实现某些功能的方法和用于初始化对象的构造方法。方法在使用时除了常规的用法外还有一些特殊的用法。例如,构造方法间的调用、使用private修饰的私有构造方法、使用可变长参数的方法等。
3.2.1 在构造方法中调用其他构造方法
为了某些特定运算的需要,Java允许在类的某个构造方法内使用this关键字调用其他构造方法,采用这种形式可使程序代码更加简练。
例如,下列代码创建了一个Circle(圆)类,该类拥有radius(半径)、height(高)和color(颜色)3个私有字段;拥有一个带有3个参数和一个无参数的构造方法。若要求在使用无参数构造方法创建Circle类的对象时,能自动为上述3个私有字段赋以一些特定值,则可在该构造方法内通过this关键字调用带有3个参数的构造方法来实现。

在程序中使用new关键字创建Circle类的对象时,以下两个语句的执行结果是完全相同的。可以看出如果radius=2,height=5,color="blue"是一种常用的状态组合的话,使用上述无参数构造方法的确十分方便。

需要注意以下两点:
1)在一个构造方法中调用另一个构造方法时,必须使用this关键字,不能使用被调用的构造方法名。例如,下列语句是错误的。

2)在一个构造方法中使用this关键字时,如果方法体语句中有多行语句,则包含this的语句必须写在方法体语句的第一行。
3.2.2 私有构造方法和单例模式
类的构造方法成员通常是在使用new关键字创建类对象(实例化)时,由系统自动调用的。所以,其构造方法一般不能使用private修饰符。但在某些特殊的应用场景中,可能需要限制外部程序创建类对象的数量,以减少对系统资源的占用。单例模式(Singleton Pattern)的应用就是这样的一个特例。
所谓单例模式是一种特殊的创建类对象的模式。在该模式中要求某个类只有一个自动实例化的对象,并且能向整个系统提供这个实例。具有该特征的类也称为单例类。单例类可以通过使用private修饰符的私有构造方法来实现。
1.创建单例类
下列代码创建了一个名为Singleton的类,该类的构造方法被声明成私有的。外部程序需要创建该类对象时只能通过调用类的getObject()静态方法来实现。但是,getObject()方法的返回值永远都是同一个Singleton类的对象obj。

2.单例模式的优缺点
在程序中使用单例模式具有如下一些优点。
1)由于单例模式在内存中只有一个实例,减少了内存开支。特别是一个对象需要频繁地创建、销毁时,单例模式的优势就更加明显了。
2)由于单例模式只生成一个实例,所以减少了系统的性能开销。当一个对象的产生需要比较多的资源时,如读取配置、产生其他依赖对象时,就可以通过在应用启动时直接产生一个单例对象,然后用永久驻留内存的方式来解决。
3)单例模式可以避免对资源的多重占用。例如,一个写文件动作,由于只有一个实例存在内存中,就可避免对同一个资源文件的同时写操作。
4)单例模式可以在系统中设置全局访问点,优化和共享资源访问。例如,可以设计一个单例类负责所有数据表的映射处理。
任何一个事物都会有正反两个方面,单例模式也不例外。在程序中使用单例模式时要充分认识到单例模式一般没有接口,扩展很困难。若要扩展,除了修改代码基本上没有第二种途径可以实现。
3.单例模式的使用场景
单例模式的使用场景主要有以下几个方面。
1)要求生成唯一连续标识(如序列号、编号等)的环境。
2)创建一个对象需要消耗的资源过多,如要访问IO和数据库等资源的环境。
3)需要定义大量的静态常量和静态方法(如工具类)的环境。
3.2.3 参数长度可变的方法
在JDK1.5之后,Java允许在定义方法时使用长度可变参数,也就是允许为方法指定数量不确定的形参。如果在定义方法时,在最后一个形参类型的后面增加3个点符号“…”,则表示该形参可以接收多个参数值。
例如,下列代码声明的getTotal()方法中包含一个常规参数id(学号)和一个可变长参数grades(各科成绩)。调用语句可以将一个学号值和若干个成绩值传递给getTotal()方法以获取学生的总分值。从代码中可以看出getTotal()方法的可变长参数grades实际上是一个一维数组,通过遍历数组各元素即可计算出总分值。

在程序中可按如下所示的方式调用getTotal()方法以获取有不同科目数量的总分值。
