一般来说,最好能重用对象而不是在每次需要的时候就创建一个相同功能的新对象。
demo1:
String s = new String("hello world");
需要改成
String s = "hello world";
因为第一种写法,每一次调用的时候都会创建一个新的String实例。但是第二种写法,在同一台虚拟机中运行的代码,只要他们包含相同的字符串字面常量,就会被重用。
对于同时提供了静态工厂方法(见第1条)和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。
除了重用不可变的对象之外,也可以重用那些已经不会被修改的可变对象。
错误方式:
isBabyBoomer每次被调用,都会新建一个Calendar、一个TimeZone和两个Date实例。
正确方式:
Map接口的keySet方法返回该Map对象的Set视图,每次调用keySet都返回同样的Set实例。当其中一个返回对象发生变化时,所以其他的返回对象也要发生 变化。
自动装箱(autoboxing):
将sum的生命从Long改为long,运行速度提成了7倍。
demo:
(但是,有些场景重用对象,比创建新对象付出的代价要高很多--详细见第39条:保护性拷贝defensive copying)
demo1:
String s = new String("hello world");
需要改成
String s = "hello world";
因为第一种写法,每一次调用的时候都会创建一个新的String实例。但是第二种写法,在同一台虚拟机中运行的代码,只要他们包含相同的字符串字面常量,就会被重用。
对于同时提供了静态工厂方法(见第1条)和构造器的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。
除了重用不可变的对象之外,也可以重用那些已经不会被修改的可变对象。
错误方式:
isBabyBoomer每次被调用,都会新建一个Calendar、一个TimeZone和两个Date实例。
- // Creates lots of unnecessary duplicate objects - page 20-21
- import java.util.*;
- 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;
- }
- }
正确方式:
- // Doesn't creates unnecessary duplicate objects - page 21
- import java.util.*;
- 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;
- }
- }
Map接口的keySet方法返回该Map对象的Set视图,每次调用keySet都返回同样的Set实例。当其中一个返回对象发生变化时,所以其他的返回对象也要发生 变化。
自动装箱(autoboxing):
将sum的生命从Long改为long,运行速度提成了7倍。
demo:
- public class Sum {
- // Hideously slow program! Can you spot the object creation?
- public static void main(String[] args) {
- long beginTime = System.currentTimeMillis();
- System.out.println(beginTime);
- Long sum = 0L;
- for (long i = 0; i < Integer.MAX_VALUE; i++) {
- sum += i;
- }
- System.out.println(sum);
- long endTime = System.currentTimeMillis();
- System.out.println(endTime);
- System.out.println((endTime-beginTime)/1000);
- }
- }
(但是,有些场景重用对象,比创建新对象付出的代价要高很多--详细见第39条:保护性拷贝defensive copying)