第三条
通过私有构造函数强化不可实例化的能力
只包含静态方法和静态域的类,可以把操作在原语类型的值或者数组类型上的相关方法组织起来,如java.lang.Math或者java.util.Arrays,也可以把操作在实现特定接口的对象上的方法组织起来,如java.util.Collections。我们还可以利用这种类把操作在final类上的方法组织起来,以取代扩展该类的做法。
这样的工具类(utility class)不希望被实例化,而在缺少显示构造函数的情况下,编译器会自动提供一个公有的、无参默认构造函数。防止它被实例化的方法是,
让这个类包含单个显式的私有构造函数。在使用的时候,最好对构造函数的作用增加一些注释。
这样使用的副作用是使得一个类不能被子类化。所有的构造函数都必须要调用一个可访问的朝类构造函数,无论显示地或隐式地调用,这种情况下,子类没有可访问的构造函数来调用了。
第四条
:避免创建重复的对象
重复使用同一个对象,而不是每次需要的时候就创建一个功能上等价的新对象。如果一个对象是非可变的(immutable),那么它总是可以被重用。
String s = new String(“silly”);
该句每次被执行都创建一个新的String实例,”silly”本身就是一个String实例。
改进版本: String s = “No longer silly”;
该版本只使用一个String实例,而且对于所有在同一个虚拟机中运行的代码,只要它们包含相同的字符串字面常量,则该对象就会被重用。
对于同时提供了静态工厂方法和构造函数的非可变类,通常可以利用静态工厂方法而不是构造函数,以避免创建重复的对象。
除了重用非可变的对象外,对于已知不会被修改的可变对象,也可以重用他们。
public
class
Person {
private
final
Date
birthDate
;
public
Person(Date birthDate){
this
.
birthDate
= birthDate;
}
public
boolean
isBabyBoomer(){
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone(
"GMT"
));
gmtCal.set(1946, Calendar.
JANUARY
,1,0,0,0);
Date boomStart = gmtCal.getTime();
gmtCal.set(2008, Calendar.
JANUARY
,1,0,0,0);
Date boomEnd = gmtCal.getTime();
return
birthDate
.compareTo(boomStart) >=0 &&
birthDate
.compareTo(boomEnd)<0;
}
}
这些Calendar,TimeZone和两个Date一般不会被修改,但每次isBabyBoomer被调用的时候,都会创建他们。下面的代码提高了效率:
public
class
Person {
private
final
Date
birthDate
;
public
Person(Date birthDate){
this
.
birthDate
= birthDate;
}
private
static
final
Date
BOOM_START
;
private
static
final
Date
BOOM_END
;
static
{
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone(
"GMT"
));
gmtCal.set(1946, Calendar.
JANUARY
,1,0,0,0);
BOOM_START
= gmtCal.getTime();
gmtCal.set(2008, Calendar.
JANUARY
,1,0,0,0);
BOOM_END
= gmtCal.getTime();
}
public
boolean
isBabyBoomer(){
return
birthDate
.compareTo(
BOOM_START
) >=0 &&
birthDate
.compareTo(
BOOM_END
)<0;
}
}
如果
isBabyBoomer
方法被频繁调用,则将会带来显著的性能提高。但如果该方法不会被调用,则没有必要初始化
BOOM_START
和
BOOM_END
域。
并不是所有的对象都能够重用,考虑适配器的情形。适配器:把功能委托给后面的一个对象,从而为后面的对象提供一个可选的接口。由于适配器出来后面的对象之外,没有其他的状态信息,所以针对某个给定对象的特定适配器而言,它不需要创建多个适配器实例。
小对象的创建和回收是廉价的,所以通过创建附加的对象以使程序更清晰,简洁,功能强大也是好事。反之,滥用对象池(object pool)来避免对象的创建是不明智的,除非池中的对象是非常重量级的,比如数据库连接池。一般而言,维护对象池会把代码弄乱,增加内存占用(footprint),并且还损害性能。