《effective java》第二章 创建和销毁对象
第二章 创建和销毁对象
本文在看《effective java》第二章后所写
第一条静态工厂代替构造方法
几大优势:
1.静态工厂有名称,产生的客户端代码更容易被被识别。
2.不必再每次调用的时候创建一个新对象,(例如 单例....)。
3.他可以返回原返回类型的任何子类型的对象。由此衍生出服务提供者框架 (在jdbc源码中能够看到,可以参考我的这篇文章 https://juejin.im/post/6854573220817797134 ),阅读这一节感触最大的就是这一条以及其应用,从源码中找到了原型,并进行了理解
4.在创建参数化类型实例的时候,他们使代码变得更加简洁,例如使用泛型。
第二条:遇到多个构造器参数时要考虑用构建器
因为构建器,能够更加直白的告诉你需要哪些参数,哪些是必须的,构造起来不那么容易出错
第三条:用私有函数或者枚举类型强化Singleton属性
当自己编写单例不是枚举类型时提几个必要的点,1.构造函数需要私有化,2.防止有人使用反射创造一个新对象,建议当已有实例对象时,再次调用构造函数时构造函数抛出异常。3.你还需要实现序列化,并且重写 readResolve方法,若没有重写readResolve则在反序列化时会新建一个对象。( https://juejin.im/post/6844904142402486285 讲解了为什么重写readResolve则在发序列化时不会新建一个对象)
还是比较建议使用枚举进行单例,个人觉得单例中的懒汉式看起来比饿汉式优化,未使用时占用资源少,但在你使用时他终究还是会占用资源,最多是延缓他占用空间的时期,我更觉得饿汉式更能在测试阶段帮助你发现内存是否在未来会不足。
在此简单分析一下eumn如何保证单例
这是反编译后的枚举类,可以很清楚的看出他是继承了Enum,而Enum中又有什么呢
/**
* prevent default deserialization
*/
private void readObject(ObjectInputStream in) throws IOException,
ClassNotFoundException {
throw new InvalidObjectException("can't deserialize enum");
}
private void readObjectNoData() throws ObjectStreamException {
throw new InvalidObjectException("can't deserialize enum");
}
从上面代码可以看出,如果你没重写序列化的方法,则会抛出此异常。它能够保证单例。
第四条:通过私有构造器强化不可实例化的能力
假设你写了一个工具类,里面有很多静态方法,但有的人就是喜欢用对象来调用静态方法,你若想屏蔽掉这种可能可以直接将构造函数私有化,为了防止有人用反射,你在构造函数中抛出异常可以完全可以的
第五条:避免创造不必要的对象
其实就是能重复利用的对象就重复利用,这一点在基本类型的包装类型中用的极多基本所有包装类型有缓存了一些范围的常量,在设计模式中称为"享元模式",比如 Integer.valueOf(),这个语法糖在自动拆箱装箱中常用,可以自行查看反编译代码。还有String,这个存在常量池的对象。所以说 如果你经常new String(“”),那就真的求求你考虑一下内存吧!
第六条:消除过期的对象引用
意思为以后不要使用的对象请把它移除那个强引用,不要继续将他放入强引用的对象中,例如一个静态变量的List数组,不要的请及时remove。说到这就想到了ThreadLocal的内存泄漏,如果在这里将的话篇幅较长,下次单独写一篇文章出来。记住一点不要用了的请及时remove掉
第七条:避免使用终结方法
所谓的终极方法即finalizer,为什么最好别用这个原因就是你不知道这个对象什么时候会被回收,所以完全不确定什么时候这个方法会被执行,于是不建议使用此方法