创建和销毁对象

相比于构造函数,考虑使用静态工厂方法

如果自己写的类,希望客户端能创建它的实例,一般自己要提供哪些方式?
  • 提供公有构造函数
  • 提供公有静态工厂方法
公有静态工厂方法有什么优点?
  • 它有名字,代码易于理解
  • 它可以避免创建不必要的重复对象
  • 它可以返回该类型的任何子类型的实例
公有静态工厂方法有什么缺点?
  • 仅仅提供公有静态工厂方法,而不提供公有或受保护的构建函数,该类将不能被继承。但可以考虑使用组合来弥补该缺点。
  • 它不容易被程序员发现
公有静态工厂方法惯用命名有哪些?
  • from
  • of
  • valueOf
  • instance or getInstance
  • create or newInstance
  • getType
  • newType
  • type

当面对多个构造函数参数时,考虑使用Builder模式

静态工厂和构造函数的缺点有哪些?
  • 当构造函数的参数,尤其是可选参数,越来越多时,扩展性不好,不易阅读
JavaBeans模式的缺点有哪些?
  • 由于构建过程被分为多步,该实例可能会造成不一致的状态
  • 妨碍该类的不可变性
Builder模式解决了静态工厂和构造函数,以及JavaBeans的缺点,但它自身有哪些缺点?
  • 为了创建对象,必须首选创建它的Builder

利用私有构造函数和枚举,以加强单例特性

解释单例
  • 仅仅被实例化一次的类
怎么实现单例?
  • 公有的static final 域
  • 公有的static工厂方法
  • 利用枚举类
利用公有的static final域或static工厂方法实现单例的缺点有哪些?
  • 反射攻击问题。
  • 复杂的序列化问题。
针对上一条的缺点和问题,有哪些解决办法?
  • 针对反射攻击:修改构造函数,使其当发现创建第二个实例时,throw an exception。
  • 针对序列化问题:添加implements Serializable, 所有的实例域前添加transient,添加readResolve方法
private Object readResolve() {
  return INSTANCE;
}
除了上述的解决办法,有没有更简单的办法?
  • 使用枚举类创建单例,可以同时解决反射攻击和序列化的问题。

利用私有构造函数,使类不能被实例化

你写了个工具类,不希望该类被人实例化,有什么办法?
  • 该类设为final
  • 添加私有构造函数,并在私有构造函数内部添加
throw new AssertionError();

不要硬编码resources,而是要选择dependency injection

  • 不要用静态工具类或单例实现依赖underlying resources的类,不要让该类直接创建该resources,而是要用依赖注入,即把这些resources传入到constructor 或者 static factory 或者 builder 来创建。或者使用Spring等其他框架创建。

为了避免创建不必要的对象,有哪些建议?

  • 再利用单例,而不是重新创建功能一样的实例。
  • 优先使用静态工厂方法,而不是每次都用构造函数创建新对象。比如
Boolean.valueOf(String) 而不是 Boolean(String)
  • 合理使用cache,利用static final 域 事先cache一些耗性能的对象创建。
  • 合理使用代理,比如Map对象中的keySet方法
  • 警惕无意识的autoboxing

消除无用的对象引用,有哪些建议?

  • 该对象赋值为null
  • 尽量减少该对象的scope
  • 巧用WeakHashMap

为什么不要用finalizers and cleaners,不要用System.gc和System.runFinalization?

  • 它们不能保证及时的执行
  • 它们可能被终止
  • 使用finalizers,会导致 uncaught exception 将被ignored
  • 都会带来性能损失
  • 存在安全问题

相对try-finally,为什么优先使用try-with-resources

  • try-with-resources更简洁
  • try-with-resources 生成的exception更有帮助性


你可能感兴趣的