Effective Java:Ch2_创建销毁对象:Item5_避免创建不必要的对象
通常最好重用单个对象,而不是在每次需要时都创建一个功能完全一样的新对象。重用不仅更快而且更流行。如果对象是不可变的(Immutable,Item15),那它总是能被重用的。
看下面这个极端的反例:
// Hideously slow program! 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实例(大约每次long类型的i和Long类型的sum相加时就会创建一个)。将Long修改为long后,在我的机器上的运行时间从43秒降为6.8秒。教训很明显:优先使用基本类型,而不是装箱基本类型;并且当心不经意的自动装箱。
本条目并不是说创建对象代价很昂贵,于是要避免创建对象;相反,由于小对象的构造函数只做少量的显式工作,其创建与回收的代价是很小的,尤其是在现代JVM实现上。通过创建附加对象提高程序的清晰性、简洁性、功能性通常是件好事。
相反,通过维护自己的对象池来避免创建对象则是一个坏主意,除非对象池里的对象是非常重量级的。正确使用对象池的一个经典例子是数据库连接。建立数据库连接的成本是非常高的,所以重用这些对象是有意义的。同时,数据库license可能限制你只能建立一定数量的连接。但是,一般而言,维护自己的对象池会把代码弄得混乱,增加内存占用,损害性能。现代JVM实现具有高度优化的垃圾回收器,性能很容易就超过轻量级对象的对象池。
和本条目对应的是Item39,关于保护性拷贝(defensive copying)的条目。
Item5:当应该重用一个已存在的对象时,就不要创建新对象;Item39:当应该创建一个新对象时,就不要重用已存在的对象。注意,当需要保护性拷贝时却重用对象带来的代价,要远远大于创建不必要的多余对象的代价。当需要进行保护性拷贝却未做到,可能会导致潜在的bug和安全漏洞;而创建不必要的对象仅仅只影响编码风格和性能而已。