effective java读书笔记5:避免创建不必要的对象
2017-01-19 00:00
411 查看
摘要: 创建和销毁对象
解读:如果不需要每次都创建一个相同功能的新对象,最好重用对象,因为有时候反复创建同样的对象是有代价的。
例如:
1、String 的初始化我们一般不会调用String s = new Sring("fs"),如果用在循环中,则会找出不必要的浪费(每次都会在堆中new一段空间出来)。而对于String s="fs"这种方式,jdk有常量池概念,反复地调用则会被重用。
2、每次调用isBabyBoomer方法的时候都会做重复的动作,实例化两个对象:boomStart 和boomEnd,而这两个对象实际上每次调用都是一样重复的,因此完全可以只保存一份实例即可,因此比较合理的作法是定义成两个静态的成员变量,第一次加载类的时候实例化,后续不在实例化了。
不合理的写法:
改进的写法:
当然文中也提到了延迟初始化那两个日期对象的问题,也就是说在不调用isBabyBoomer方法的时候初始化这两个对象实际上意义不大(正如单例模式为什么懒加载的方法),但是作者并不推荐,这样会使方法变得更加复杂(这一点具体情况具体分析吧,也就是在性能的优化和复杂程度上如何做权衡了)。
3、文中讲的是适配器的形式。这一点没看懂,后面再仔细研究!
4、优先使用基本类型而不是装箱类型,要当心无意识的装箱。例如下面的一段代码,sum定以的类型是基本类型long的包装类Long,每加一次意味要实例化一次(和不提倡对String类型的字符串做反复的修改操作同样的道理,因为都是不可变类,必定造成堆空间的浪费),同时还有一次拆箱的操作。一次性能上是有一定的影响。因此尽量用基本类型。
总结:适当情况下考虑对象的重用,避免创建不必要的对象,灵活运用,但不能一概而论!具体情况具体分析!
解读:如果不需要每次都创建一个相同功能的新对象,最好重用对象,因为有时候反复创建同样的对象是有代价的。
例如:
1、String 的初始化我们一般不会调用String s = new Sring("fs"),如果用在循环中,则会找出不必要的浪费(每次都会在堆中new一段空间出来)。而对于String s="fs"这种方式,jdk有常量池概念,反复地调用则会被重用。
2、每次调用isBabyBoomer方法的时候都会做重复的动作,实例化两个对象:boomStart 和boomEnd,而这两个对象实际上每次调用都是一样重复的,因此完全可以只保存一份实例即可,因此比较合理的作法是定义成两个静态的成员变量,第一次加载类的时候实例化,后续不在实例化了。
不合理的写法:
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; } }
改进的写法:
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; } }
当然文中也提到了延迟初始化那两个日期对象的问题,也就是说在不调用isBabyBoomer方法的时候初始化这两个对象实际上意义不大(正如单例模式为什么懒加载的方法),但是作者并不推荐,这样会使方法变得更加复杂(这一点具体情况具体分析吧,也就是在性能的优化和复杂程度上如何做权衡了)。
3、文中讲的是适配器的形式。这一点没看懂,后面再仔细研究!
4、优先使用基本类型而不是装箱类型,要当心无意识的装箱。例如下面的一段代码,sum定以的类型是基本类型long的包装类Long,每加一次意味要实例化一次(和不提倡对String类型的字符串做反复的修改操作同样的道理,因为都是不可变类,必定造成堆空间的浪费),同时还有一次拆箱的操作。一次性能上是有一定的影响。因此尽量用基本类型。
public class Sum { // Hideously slow program! Can you spot the object creation? public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); } }
总结:适当情况下考虑对象的重用,避免创建不必要的对象,灵活运用,但不能一概而论!具体情况具体分析!
相关文章推荐
- 第五条——避免创建不必要的对象
- Effective Java 第5条 避免创建不必要的对象
- 避免创建不必要的对象和避免使用终结方法
- Item 5 避免创建不必要的对象
- 避免创建不必要的大对象(把大对象转换为小对象)
- Java学习笔记5:避免创建不必要的对象
- Android 编码规范:(五)避免创建不必要的对象
- Android 编码规范:(五)避免创建不必要的对象
- 《Effective Java》读书笔记04--避免创建不必要的对象
- Effective Java之避免创建不必要的对象
- Java学习笔记5:避免创建不必要的对象
- 《Effective java》读书笔记1——避免创建不必要的对象
- Effective Java (5) 避免创建不必要的对象
- 避免创建不必要的SPWeb对象
- Effective Java (5) - 避免创建不必要的对象
- Java学习笔记5:避免创建不必要的对象
- 第5条:避免创建不必要的对象
- 【Effective Java】Ch2_创建销毁对象:Item5_避免创建不必要的对象
- 05、避免创建不必要的对象
- Android 编码规范:(五)避免创建不必要的对象