一般來說,我們最好能夠重用對象,而不是每次需要的時候都去創建一個相同的對象。
重用對象即快速,又流行,如果對象時不可變的,它就始終可以被重用。
下面有一個反面的例子:
String s=new String("string");
該語句每次被執行都會創建一個新的String實例,但是這是不必要的,傳遞給String構造器的參數本身就是一個String實例,
功能方面等同於構造器創建的所有對象,如果這是一個被頻繁調用的方法中,就會創建出成千上萬不必要的String實例。
可以改進爲如下所示:
String s="String";
除了重用不可變的對象之外,也可以重用那些已知不會被修改的可變對象。
下面是一個反面的例子:
public class Person {
private Date 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(1965,Calendar.JANUARY,1,0,0,0);
Date boomEnd=gmtCal.getTime();
return birthDate.compareTo(boomStart)>=0 &&
birthDate.compareTo(boomEnd)<0;
}
}
上面代碼isBabyBoomer每次被調用,都會創建一個Calendar,一個TimeZone和倆個Date實例,這是完全不必要的。
下面使用一個靜態初始化器,避免了這種低效的情況:
public class Person {
private static Date 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(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;
}
}
改進後的代碼,只有在第一次初始化的時候纔會去創建需要的實例。
如果isBabyBoomer方法永遠不被調用,那就沒有必要初始化那些BOOM_START和BOOM_END,
我們可以通過延遲加載,來避免這個問題,把BOOT_START和BOOM_END的初始化,放在第一次調用isBabyBoomer方法的時候進行。
在JAVA1.5的髮型版本中,加入了自動裝箱拆箱,如果不小心使用,也會導致創建不必要的對象,如下:
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,就意味着要創建大約2的32次方個多餘的Long實例,所以導致了導致了計算較慢,如果把Long改成long就會快很多了。