Effective Java - 创建和销毁对象

静态工厂方法代替构造器

优点

  • 包含名称易于阅读
  • 避免创建不必要的重复对象
  • 可以返回原返回类型的子类型,类型更加灵活
  • 创建参数化类型实例代码更简洁

缺点

  • 静态方法所在类没有public或者protected的构造器无法子类化
  • 实际上和其他静态方法没有区别

多个构造器参数考虑构建器

  • 静态工厂和构造器不能很好地扩展到大量的可选参数
  • 重叠构造器模式可行参数多时,难写且阅读困难
  • 构造JavaBean过程中可能处于不一致状态
  • JavaBean模式阻止把类做成不可变的可能,需要额外确保线程安全
  • Builder模式,既有JavaBean良好的可读性,又有重叠构造器的安全性
    • 适用场景:静态方法或构造器参数较多,特别是可选参数多
    • 劣势:ORM框架依赖java bean的set和get方法

用私有构造器或枚举类型强化单例属性

私有构造器

  • 通过反射机制调用私有构造器攻击setAccessible(true),在修改构造器创建第二个实例时抛异常
  • 反序列化会生成新的实例,提供readResolve方法返回原有实例

单元素枚举类型

  • 反射与反序列化时防止多次实例化

避免使用终结方法

  • 终结方法不能保证及时执行,不能保证会被执行
  • 非常严重的性能损失
  • 终止对象中封装的资源应提供显式终止方法

    1
    inputstream/outputstream/connection的close方法 或Timer的cancel方法
  • 终结方法好处

    • 忘记调用显式方法时可充当“安全网”
    • 终结对象的本地对等体,终止非关键的本地资源

私有构造器强化不可实例化

只包含静态方法和静态域的类,工具类不具有任何实例化意义

该类组织起来的两种特性

  • 基本类型的值或者数组类型上的相关方法组织起来

    1
    java.lang.Math/java.util.Arrays
  • 实现特定接口的对象上的静态方法(包括工厂方法)组织起来.

    1
    java.util.Collections

避免创建不必要的对象

  • 当心无意识的自动装箱
  • 适配器:把功能委托给后备对象,为后备对象提供一个可替代接口,它没有其他状态信息,不需要多个实例
  • 重用不可变对象

    • 字符串字面常量
    • 静态工厂方法优先.
      1
      Boolean.valueOf(String)
  • 重用已知不会被修改的可变对象

    • Calendar实例的创建代价特别昂贵
    • 延迟初始化lazily initializing,但是方法实现更加复杂,难以提高性能
  • 维护轻量级线程池避免重复创建对象不是好做法。原因:维护代码跟高度优化的现代JVM垃圾回收相比性能太差
  • “保护性拷贝”如果重用现有对象会导致潜在错误或安全漏洞,最好创建新的对象

小对象创建回收在现代jvm上非常廉价。通过创建附加对象,提升程序清晰性、简洁性和功能性,通常是个好事。不必要的对象只会影响程序风格和性能。

消除过期对象引用(内存泄漏)

  • 一单对象引用已经过期需要清空这些引用,即赋值为null
  • 清空应该是一种例外而不是规范行为。通过紧凑的作用域范围定义变量,结束生命周期后自然会清空。
  • 内存泄漏常见来源是缓存。定时清除或在加入新缓存时清除。
    • 后台线程TimerScheduledThreadPoolExecutor完成定时清除
    • LinkedHashMapremoveEldestEntry方法添加时清除最旧的条目。
    • 复杂缓存必须直接使用java.lang.ref
  • 监听器和其他回调也是内存泄漏常见来源,只保存回调、监听器的弱引用。比如保存成WeakHashMap的键
  • 通过仔细的代码检查或Heap剖析工具能发现内存泄漏问题