一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。重用方式既快速,又流行。如果对象是不可变的,它就始终可以被重用。
举个栗子 1:
一个极端的语句:
String s = new String("GoodMan");
该语句每次执行都会创建一个新的String 实例,很明显这样的功能一样的实例是完全没有必要的。
改进:
String s = "GoodMan";
这样不论执行多少次,调用的都是同一个实例。只要包含相同的字符串字面常量,该对象就会被重用。
*对于同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要对象。
举个栗子2:
除了重用不可改变的对象之外,也可以重用那些已知不会被修改的可变对象。
效率低的版本 :
public class Person {
private final Date birthDate;
public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
}
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(1965, Calendar.JANUARY, 1, 0, 0, 0);
Date boomEnd = gmtCal.getTime();
return birthDate.compareTo(boomStart) >= 0 &&
birthDate.compareTo(boomEnd) < 0;
}
}
效率高的版本 :
class Person {
private final Date birthDate;
public Person(Date birthDate) {
this.birthDate = new Date(birthDate.getTime());
}
//创建重用可变化的Date对象
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(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END = gmtCal.getTime();
}
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START) >= 0 &&
birthDate.compareTo(BOOM_END) < 0;
}
}
改进后的Person类只在初始化的时候创建Calendar,TimeZone和Date实例一次,而不用每次调用isBadyBoomer的时候都创建这些实例。如果isBadyBoomer方法被频繁的调用,改进的后的方法将明显的提高性能。
举个栗子 3:
1.5版本中,有一种创建多余对象的新方法,称作自动装箱,允许我们将基本类型和装箱基本类型混用,按需要自动装箱和拆箱。看看下面这段代码:
public class Sum {
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
System.out.println(sum);
}
}
虽然计算结果完全正确,但是比实际计算要更慢一些。因为变量sum被申明成Long 而不是 long,这就意味者这段代码执行,在循环中构造了2^31个多余的Long实例。这样是非常低效的。
*要优先使用基本类型而不是自动装箱基本类型,要当心无意识的自动装箱。