1. 如果对象是不可变的(immutable),它就始终可以被重用。
(1) 特别是String类型的对象。
String str1 = new String("str"); // 创建许多不必要的实例 String str2 = "str"; // "str"其本身是一个String实例,对于所有同一台虚拟机中运行的代码,只要它们包含相同的字符串字面常量,该对象就会被重用
(2) 同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器。
2. 如果可变对象是已知不会被修改的,它也可以被重用。
import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class Person { private final Date birthday; // ... 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 birthday.compareTo(boomStart) >= 0 && birthday.compareTo(boomEnd) < 0; } }
如果isBabyBoomer()经常被调用,那么每一次都要创建Calendar,Date的实例,效率低下。以下方式提高了性能,代码含义也更加的清晰。
import java.util.Calendar; import java.util.Date; import java.util.TimeZone; public class Person { private final Date birthday; 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 birthday.compareTo(BOOM_START) >= 0 && birthday.compareTo(BOOM_END) < 0; } }
创建多余对象的新方法:自动装箱(autoboxing)。但要优先使用基本类型而不是装箱基本类型,要当心无意识的自动装箱,不然会创建多个多余的实例。
(与第39条呼应)因重用对象而付出的代价要远远大于因创建重复对象而付出的代价时,提倡使用保护性拷贝。
比如除非池中的对象是非常重量级的(数据库连接池),否则不要维护自己的对象池(object pool)。一般维护自己的对象池必定会把代码弄的很乱,同时增加内存占用,并且还会损害性能。
必要时候没实施保护性拷贝,会导致潜在的错误和安全漏洞。
不必要的创建对象,会影响程序的风格和性能。