通常来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。重用方式既快速、又流行。如果对象是不可变的(immutable),它始终可以被重用。
首先举一个反面例子
String result=new String("oschina");
该语句每执行一次就会创建一个String实例,如果这在一个循环中,将会有很多String实例被创建,有可能会创建成千上万的实例,显然这是不必要的。上面的代码可以这样修改
String result="oschina";
这种写法只用了一个String实例,而不是每次都创建一个实例。 这样可以保证,对于所有在同一台虚拟机中运行的代码,只要它们包含相同的字符串字面常量,该对象就会被重用。
其次,对于同时提供了静态工厂方法和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。例如,静态工厂方法Boolean.valueOf(String)几乎总是优先于构造器Boolean(String)。构造器在每次被调用的时候都会创建一个新的对象,而静态工厂方法则从来不要求这样做,实际上也不会这样做。
除了重用不可变的对象之外,也可以重用那些已经不会被修改的可变对象。
反面例子
public class Person {
private final Date birthDate;
public Person(Date birthDate) {
// Defensive copy - see Item 39
this.birthDate = new Date(birthDate.getTime());
}
// Other fields, methods omitted
// DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
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实例,这显然是不必要的。
对于上面的代码可以这样修改
class Person {
private final Date birthDate;
public Person(Date birthDate) {
// Defensive copy - see Item 39
this.birthDate = new Date(birthDate.getTime());
}
// Other fields, methods
/**
* The starting and ending dates of the baby boom.
* 静态变量一般需要大写
*/
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;
}
这样把每次需要调用的变量放到static静态块里面,这样就保证了避免频繁被调用的次数。从而使性能得到提高。
在Java 1.5 的发行版本中,有一种创建多余对象的新方法,称作自动装箱(autoboxing),它允许程序员将基本类型和装箱基本类型混用,按需自动装箱和拆箱。
public class Sum {
// Hideously slow program! Can you spot the object creation?
public static void main(String[] args) {
LongTimes();
longTimes();
}
public static void LongTimes(){
long beginTime = System.currentTimeMillis();
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
long endTime = System.currentTimeMillis();
System.out.println("Long====总数:"+sum);
System.out.println("Long====耗时:"+(endTime-beginTime)/1000);
}
public static void longTimes(){
long beginTime = System.currentTimeMillis();
long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
sum += i;
}
long endTime = System.currentTimeMillis();
System.out.println("long====总数:"+sum);
System.out.println("long====耗时:"+(endTime-beginTime)/1000);
}
这种Long和long计算的结果如下,只因为将变量sum声明为Long而不是long,从而多计算了2*31次方,所以结论很明显,要优先使用基本类型而不是自动封装类型,要当心无意识的自动封装。