您的位置:首页 > Web前端

Effective Java Item5-在可以重用对象的时候避免创建对象

2009-07-08 00:53 591 查看
Item5 Avoid creating unnecessary objects
避免创建不必要的对象

一般情况下,最好重用功能上对等的对象,而不是创建新的对象。重用对象可以提高性能,并且样式良好。如果对象是immutable的(private fields, no setter methods),那么重用起来就比较方便。
不良例子:
String name = new String(“HelloWorld”);
每次执行时,都会创建一个新的String对象。其中构造方法的参数本身就是一个对象,这样的构造方法没有必要,如果这样的语句出现在循环中,将会导致非常多的不必要的对象的创建。
修正:
String name = “HelloWorld”;
该语句创建了单一的对象。这个对象还可以被之后运行在同一个虚拟机总的其他使用相同字符串的代码重用。
package com.googlecode.javatips4u.effectivejava.unnecessary;

public class UnnecessaryObjectsSample {

public static void main(String[] args) {
long nanoTime = System.nanoTime();
String name = null;
for (int i = 0; i < 10000; i++) {
// DO NOT DO THIS
name = new String("name");
}
System.out.println(System.nanoTime() - nanoTime);// 2262299
nanoTime = System.nanoTime();
for (int i = 0; i < 10000; i++) {
// CHANGE TO THIS
name = "name";
}
System.out.println(System.nanoTime() - nanoTime);// 867987
System.out.println(name);
}
}
可以使用工厂方法来避免创建不必要的对象。
package com.googlecode.javatips4u.effectivejava.unnecessary;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class BadMutableObjectUsage {

private final Date birthDate = null;

// DON'T DO THIS!
public boolean isBabyBoomer() {
// Unnecessary allocation of expensive object
// Here the two Date objects are immutable.
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;
}
}
上面例子中两个Date对象,即开始时间和结束时间是常量,所以不需要在isBabyBoomer方法中每次被调用时都进行创建,而应该作为类的静态变量进行static初始化。
package com.googlecode.javatips4u.effectivejava.unnecessary;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

public class BetterMutableObjectUsage {
private final Date birthDate = null;
private static final Date BOOM_START_DATE;
private static final Date BOOM_END_DATE;
static {
Calendar gmtCal = Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_START_DATE = gmtCal.getTime();
gmtCal.set(1965, Calendar.JANUARY, 1, 0, 0, 0);
BOOM_END_DATE = gmtCal.getTime();
}

// DON'T DO THIS!
public boolean isBabyBoomer() {
return birthDate.compareTo(BOOM_START_DATE) >= 0
&& birthDate.compareTo(BOOM_END_DATE) < 0;
}
}
同样,对于适配器(Adapter)模式而言,由于Adapter是由后台的对象支持的,所以对于同一个对象而言,没有必要为其创建多个适配器对象。例如Map接口的keySet方法返回Map的key set:
package com.googlecode.javatips4u.effectivejava.unnecessary;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

public class AdapterPattern {
public static void main(String[] args) {
Map<String, String> map = new HashMap<String, String>();
map.put("key", "value");
map.put("keys", "values");
// all the keySet are backed by the same Map object.
Set<String> keySet1 = map.keySet();
map.remove("keys");
Set<String> keySet2 = map.keySet();
System.out.println(keySet1 == keySet2);// true
System.out.println(keySet1.equals(keySet2));// true
}
}
对于同一个map对象,返回的Set是一样的,改变其中的一个set,其他的set也随之而变,因为他们都是由一个后台的Map对象来支持的。
另外,自动装箱(auto-boxing)操作也会带来隐式对象的创建:
public static void main(String[] args) {
Long sum = 0L;
for (long i = 0; i < Integer.MAX_VALUE; i++) {
// so many Long objects are created here.
// coz sum is Long but not long.
sum += i;
}
System.out.println(sum);
}
通过维持自定义的对象池(Object Pool)来避免创建不必要的对象是不好的,除非要创建的对象是重量级的对象。例如数据库连接。一般来讲,对象池会造成代码复杂,同时性能下降,现代的JVM的GC已经高度优化。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: