关于Effective java 这本书,自己的一些总结性的思考。篇幅可能不按照目录来,因为自己喜欢先看哪一章就直接阅读了。不过能确定的是,每一章都会有总结。欢迎大家拍砖与补充。
1. 考虑用静态工厂的方法代替构造器。优点:有名字,不必每次创建对象,返回任何子类型对象,简洁的代码。缺点:该类将不能被子类化(复合大于继承,也是优点),不方便doc工具输出文档,一般约定的命名规则:
valueOf 转换类型
getInstance 获得对象实例
newInstance 创建新的对象实例
getType 获得返回对象的类型
newType 置入返回对象的类型,在不同类中方便区别工厂方法
2. 遇到多个构造器参数(4个以上)时要考虑用构建器。重叠构造器代码冗长,后期不能有效的维护,javaBean模式的构造器在多线程下不安全,没有达到类不可变性,原因是暴露出去了setter方法。Builder模式的构造器是不错的选择。
Class A{
//属性
static class Bulid{
//属性
Bulid(){//接受初始化参数 }
Bulid a(){ Return bulid; //添加参数返回Bulid产生调用链}
..
A bulid(){ return A(this);} //构造器对象初始化A对象返回
}
A(Bulid b){ //将b中参数传递给A参数域}
}
3. 用私有构造器或者枚举类型强化Singleton属性。对于私有构造器有2种方案,导出公有的静态成员的实例与提供静态工厂返回私有的静态成员实例。但是并非安全的,采用AccessibleObject,通过反射技术可以调用私有的构造器,产生第二对象,解决方案是产生第二实例的时候抛出异常。使得Singleton序列化,(implementsSerializble)+(实例域transient)+(readResolve方法返回实例)。单元素的枚举类型是实现Singleton的最佳方案。
4. 通过私有构造器强化不可实例的能力。提供显示的构造方法比编译器提供默认的好,特别是私有的构造器,并在私有的构造器中抛出AssertionError。由于这一技术的使用,使得该类无法被子类化。
5. 避免创建不必要的对象。考虑的方向有,字符串类,static{}域,视图view(Map中的set等),自动装箱拆箱,对象池object pool。
6. 消除过期的对象引用。Stack.pop后,不使用的元素未置空引起的内存泄露,磁盘交换,严重的情况导致OOM异常。内存泄露另一个来源是缓存问题。如果key中不在保持引用,那么WeakHashMap自动清除过期的key。如果随着时间的增长,某些key可能不用了,那么采用LinkedHashMap。removeEldestEntry方法将实现这一方案。第三个来源是监听器和其他回调,采用保持弱引用的方法,即WeakHashMap的方案来处理。关于内存泄露的一个Heap剖析工具Heap
Profiler。
7. 避免使用终结方法。Finalizer的方法JVM并不一定执行,即使调用了System.gc。System.runFinalization。除非使用System.runFinalizersOnExit,Runtime.runFinalizersOnExit方法(ThreadStop,不建议使用)。尝试着使用try{}finally{}结构来显示的调用终结方法确保及时终止。如果子类覆盖了超类的终结方法,但是忘记手工调用超类的终结方法super.finalize,那么超类的终结方法将永远也不会被调用。
如果将本章内容联系到实际的编码之中呢?我也进行的思考,由于自己在类库方面开发经验很少,没有通读过jdk全部的源码,所以有些建议不一定准确。
1.当你在创建类的时候,就应当想这个类未来要做什么?是什么类型?构造参数多吗?适用经验1,2,3,4
2.当你在编写某段代码的时候,你应当想到该对象是否可以重复利用?如果是集合类,那么思考,传入的对象是否未来会不使用?如果觉得这段代码或者方法,以及涉及到该类在全局上随着运行会消耗较大的内存?那么可以尝试着使用5,6,7三个总结来处理这种问题。
毕竟上面都是一些方法论,在实践过程中,需要自己有经验的去判断如何做才是最优的(可能是目前最优,亦或者未来效果很好),这些都是不同场景下产生的,并不一定会有效的去解决。