如果一個對象是immutable的話,它總是可以被重用的。例如:
String s = new String("stringette"); // DON'T DO THIS!

這條語句每次執(zhí)行時(shí)都會創(chuàng)建新的String。增強(qiáng)的版本是:
String s = "stringette";
這種形式使用單一的String實(shí)例,而不是每次都會創(chuàng)建新的String。
使用static factory method可以避免創(chuàng)建不需要的對象。例如Boolean.valueOf(String)比Boolean(String)更具有優(yōu)勢。構(gòu)造函數(shù)每次都會創(chuàng)建新實(shí)例。而靜態(tài)工廠方不需要這樣做。
舉一個簡單的例子:
這個類包含有Date對象,這個值一旦被計(jì)算出來就從不改變。這個類構(gòu)造一個person,有一個isBabyBoomer方法,來判斷這個person是否是“baby
boomer,” 是否出生在1946年到1964年。
1
public class Person
{
2
private final Date birthDate;
3
4
// Other fields, methods, and constructor omitted
5
// DON'T DO THIS!
6
public boolean isBabyBoomer()
{
7
// Unnecessary allocation of expensive object
8
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
9
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
10
Date boomStart = gmtCal.getTime();
11
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
12
Date boomEnd = gmtCal.getTime();
13
return birthDate.compareTo(boomStart) >= 0
14
&& birthDate.compareTo(boomEnd) < 0;
15
}
16
}
isBabyBoomer方法不需要每次創(chuàng)建一個Calendar,TimeZone和兩個Date實(shí)例。為了避免不必要的創(chuàng)建,可以使用static初始化:
1
class Person
{
2
private final Date birthDate;
3
// Other fields, methods, and constructor omitted
4
/** *//**
5
* The starting and ending dates of the baby boom.
6
*/
7
private static final Date BOOM_START;
8
private static final Date BOOM_END;
9
static
{
10
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
11
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
12
BOOM_START = gmtCal.getTime();
13
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
14
BOOM_END = gmtCal.getTime();
15
}
16
17
public boolean isBabyBoomer()
{
18
return birthDate.compareTo(BOOM_START) >= 0
19
&& birthDate.compareTo(BOOM_END) < 0;
20
}
21
}
增強(qiáng)的版本中只創(chuàng)建Calendar,TimeZone和兩個Date一次。當(dāng)這個方法頻繁調(diào)用的時(shí)候性能會得到很大的提高。Calendar創(chuàng)建是開銷是很大的。
如果isBabyBoomer從未調(diào)用,BOOM_START和BOOM_END 也是不需要初始化的。可以使用lazily initializing來加載它們。但是這不是推薦的。經(jīng)常使用lazy initialization會使實(shí)現(xiàn)變得復(fù)雜,未必優(yōu)于已經(jīng)取得的性能。
在上面的例子中,很顯然是由于對象在初始化后不再修改才重用。其他場合下未必這么顯然。例如adapter,也稱為views。adaper代表一個后臺對象,提供一個可供選擇的接口給后臺對象。由于adapter沒有狀態(tài),因此不需要創(chuàng)建多個實(shí)例。
例如Map接口的keySet方法返回一個Map對象的Set視圖,包含所有map中的key值。顯然在給定的Map上每個調(diào)用keySet都會創(chuàng)建一個Set實(shí)例,但是每個調(diào)用都會返回相同的Set實(shí)例。雖然返回的Set是可變的,但是所有的對象都是一致的,當(dāng)其中一個變化了,所有的都要改變。這是因?yàn)樵谒鼈兒竺媸窍嗤腗ap實(shí)例。創(chuàng)建多個keySet視圖對象無害但無意義。
在1.5中autoboxing可以創(chuàng)建無用的對象。容許程序員混合基本類型和包裝類。自動boxing和unboxing操作。看下面的例子:計(jì)算所有正int的和。必須使用long才能保存所有正int的和。
1
// Hideously slow program! Can you spot the object creation?
2
public static void main(String[] args)
{
3
Long sum = 0L;
4
for (long i = 0; i < Integer.MAX_VALUE; i++)
{
5
sum += i;
6
}
7
System.out.println(sum);
8
}
隨著程序可以得到正確結(jié)果,但是計(jì)算會慢。主要由于一個字符的錯誤。變量sum被聲明為Long,而不是long,這意味著程序?qū)⒁獎?chuàng)建2(31)個無用的Long實(shí)例。這個教訓(xùn)是:盡量使用基本類型boxed到基本類型,當(dāng)心無意識的autoboxing。
通過創(chuàng)建對象池來避免對象創(chuàng)建不是一個好主意,除非池中的數(shù)據(jù)極其重量級。例如數(shù)據(jù)庫連接。創(chuàng)建連接的花銷很高,最好重用這個對象。
posted on 2008-06-19 21:47
一葉笑天 閱讀(210)
評論(0) 編輯 收藏 所屬分類:
JAVA技術(shù)