第二章 创建和销毁对象
1,用静态工厂方法代替构造器
对比构造器的优势:
- 它们有名称
- 不用每次创建新对象【享元模式?】
- 可以返回任何原类型的子类型
- 返回对象的类可以随着每次调用发生变化而变化
- 方法返回对象所属的类,在编写该静态工厂方法的类可以不存在
缺点:
- 类不含有公有或者保护的构造器,就不能被子类化(主要)
- 程序员很难发现他们
2,遇到多个构造器参数时要考虑使用构造器
-
重叠构造器模式
-
JavaBeans 模式
-
建造者模式(有4个以上参数时的最优解)
建造者模式也适用于类层次结构(难点,没看懂,给子类继承建造?)
3,用私有构造器或者枚举类型强化 Singleton 属性
实现Singleton两种常用方法(都要保持构造器私有):
- 公有静态成员是个 final 域
- 公有静态成员是个静态工厂方法
public static Ellvis getInstance(){return INSTANCE;}
- 声明一个包含单个元素的枚举类型
public enum Elvis{
INSTANCE;
public void leaveTheBuilding(){...}
}
4,通过私有构造器强化不可实例化的能力
5,优先考虑依赖注入来引用资源
依赖注入:当创建一个新的实例时,将该资源传到构造器中
依赖注入的对象具有不可变性
- 不要用Singleton和静态工具类来实现依赖一个或者多个底层资源的类,且该资源的行为会影响到该类的行为
- 也不要用该类来创建这些资源。
- 应该将这些资源或者工厂传给构造器(或者静态工厂,构建器),通过它们来创建类,这个实践就叫依赖注入,它大大提高了类的灵活性,可重用性和可测试性。
6,避免创建不必要的对象
自动装箱拆箱:使得基本类型和装箱基本类型的区别变得模糊,在语义上还有微妙的差别,在性能上有明显的差别,基本类型更快。
在提倡保护性拷贝的时候,因重用对象而付出的代价要远远大于因重复创建对象而付出的代价。必要时如果没能实施保护性拷贝将会导致bug和漏洞,而不必要地创建对象只会影响程序的风格和性能。
7,消除过期的对象引用
内存泄漏来源
-
过期引用
-
缓存
-
监听器和其他回调
确保回调被立即被当作垃圾回收的最佳方法是只保存它们的弱引用(weak reference),例如,只将它们保存成 Weak Hash Map
可以借助Heap剖析工具Heap Profiler 发现内存泄漏问题
8,避免使用终结方法清除方法
终结方法会导致行为不稳定,性能降低,以及可移植性问题。
清除方法不可预测,运行缓慢。
- 终结,清除方法不能被及时执行或者根本不执行。------延时终结过程
- 及时执行终结,清除方法是垃圾回收算法的一个主要功能,这种算法在不同的 JVM 实现中会大相径庭。
- 不要被 System.gc,System.**runFinalization **这两个方法迷惑,它们不一定保证终结方法会被执行,唯一声称会保证执行终结方法的两个方法是 System.**runFinalizersOnExit **以及 Runtime.runFinalizersOnExit。但是两个方法都有致命的缺陷,并且已经被废弃很久了。
- 终结方法有一个严重的安全问题:它们为终结方法攻击打开了类的大门。
合理用途:
- 当资源所有者忘记执行close方法时,终结或者清除方法可以充当安全网。
- 与对象的本地对等体(native peer)有关。垃圾回收器不会知道它,它的 Java 对等体被回收后,他不会被回收。 这时,终结,清除方法就是执行这项任务最合适的工具。
9,try-with-resources 优于 try-finally
-
在 try 块和 finally 块中的代码都会抛出异常,在这种情况下,第二个异常完全抹去了第一个异常,在异常轨迹中,完全没有关于第一个异常的记录,这在现实的系统中会导致调试变得非常复杂,虽然可以通过编写代码来禁止第二个异常保留第一个异常,但是实现起来太繁琐了
-
JDK7 引入的 try-with-resources 可以解决这些问题