在實際開發中,重用對象遠優於頻繁創建。本文結合《Effective Java》經典案例,闡述兩類對象重用的最佳實踐。
反模式:
String s = new String("haha"); // 每次執行創建新實例
若在循環或高頻調用方法中,將產生大量無用 String 實例,增加 GC 壓力。
優化模式:
String s = "haha"; // 單一實例,JVM 常量池自動重用
同一虛擬機中,相同字面量自動指向常量池同一實例。
低效寫法:isBabyBoomer() 每次調用創建 Calendar、TimeZone、Date 多個對象:
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 birthDate.compareTo(boomStart) >= 0 && birthDate.compareTo(boomEnd) < 0;
}
優化版:靜態初始化塊預創建不可變常量,方法調用零分配:
public class Person {
private final Date birthDate;
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;
}
}
效果:類加載階段一次性創建輔助對象,後續調用無任何對象分配開銷。
摘自《Effective Java》條目 6:避免創建不必要的對象