一叶笑天
雄关漫道真如铁, 而今迈步从头越。 从头越, 苍山如海, 残阳如血。
posts - 73,comments - 7,trackbacks - 0
如果一个对象是immutable的话,它总是可以被重用的。例如:
String s = new String("stringette"); // DON'T DO THIS!
这条语句每次执行时都会创建新的String。增强的版本是:
String s = "stringette";
这种形式使用单一的String实例,而不是每次都会创建新的String。
使用static factory method可以避免创建不需要的对象。例如Boolean.valueOf(String)比Boolean(String)更具有优势。构造函数每次都会创建新实例。而静态工厂方不需要这样做。
举一个简单的例子:
这个类包含有Date对象,这个值一旦被计算出来就从不改变。这个类构造一个person,有一个isBabyBoomer方法,来判断这个person是否是“baby
boomer,”  是否出生在1946年到1964年。
 1public 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, 1000);
10        Date boomStart = gmtCal.getTime();
11        gmtCal.set(1965, Calendar.JANUARY, 1000);
12        Date boomEnd = gmtCal.getTime();
13        return birthDate.compareTo(boomStart) >= 0
14                && birthDate.compareTo(boomEnd) < 0;
15    }

16}
isBabyBoomer方法不需要每次创建一个Calendar,TimeZone和两个Date实例。为了避免不必要的创建,可以使用static初始化:
 1class 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, 1000);
12        BOOM_START = gmtCal.getTime();
13        gmtCal.set(1965, Calendar.JANUARY, 1000);
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}
      增强的版本中只创建Calendar,TimeZone和两个Date一次。当这个方法频繁调用的时候性能会得到很大的提高。Calendar创建是开销是很大的。
      如果isBabyBoomer从未调用,BOOM_START和BOOM_END 也是不需要初始化的。可以使用lazily initializing来加载它们。但是这不是推荐的。经常使用lazy initialization会使实现变得复杂,未必优于已经取得的性能。
    在上面的例子中,很显然是由于对象在初始化后不再修改才重用。其他场合下未必这么显然。例如adapter,也称为views。adaper代表一个后台对象,提供一个可供选择的接口给后台对象。由于adapter没有状态,因此不需要创建多个实例。
   例如Map接口的keySet方法返回一个Map对象的Set视图,包含所有map中的key值。显然在给定的Map上每个调用keySet都会创建一个Set实例,但是每个调用都会返回相同的Set实例。虽然返回的Set是可变的,但是所有的对象都是一致的,当其中一个变化了,所有的都要改变。这是因为在它们后面是相同的Map实例。创建多个keySet视图对象无害但无意义。
  在1.5中autoboxing可以创建无用的对象。容许程序员混合基本类型和包装类。自动boxing和unboxing操作。看下面的例子:计算所有正int的和。必须使用long才能保存所有正int的和。
1// Hideously slow program! Can you spot the object creation?
2public 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}
随着程序可以得到正确结果,但是计算会慢。主要由于一个字符的错误。变量sum被声明为Long,而不是long,这意味着程序将要创建2(31)个无用的Long实例。这个教训是:尽量使用基本类型boxed到基本类型,当心无意识的autoboxing。
   通过创建对象池来避免对象创建不是一个好主意,除非池中的数据极其重量级。例如数据库连接。创建连接的花销很高,最好重用这个对象。


posted on 2008-06-19 21:47 一叶笑天 阅读(207) 评论(0)  编辑  收藏 所属分类: JAVA技术

只有注册用户登录后才能发表评论。


网站导航: