相比于构造函数,考虑使用静态工厂方法
如果自己写的类,希望客户端能创建它的实例,一般自己要提供哪些方式?
公有静态工厂方法有什么优点?
- 它有名字,代码易于理解
- 它可以避免创建不必要的重复对象
- 它可以返回该类型的任何子类型的实例
公有静态工厂方法有什么缺点?
- 仅仅提供公有静态工厂方法,而不提供公有或受保护的构建函数,该类将不能被继承。但可以考虑使用组合来弥补该缺点。
- 它不容易被程序员发现
公有静态工厂方法惯用命名有哪些?
- from
- of
- valueOf
- instance or getInstance
- create or newInstance
- getType
- newType
- type
当面对多个构造函数参数时,考虑使用Builder模式
静态工厂和构造函数的缺点有哪些?
- 当构造函数的参数,尤其是可选参数,越来越多时,扩展性不好,不易阅读
JavaBeans模式的缺点有哪些?
- 由于构建过程被分为多步,该实例可能会造成不一致的状态
- 妨碍该类的不可变性
Builder模式解决了静态工厂和构造函数,以及JavaBeans的缺点,但它自身有哪些缺点?
利用私有构造函数和枚举,以加强单例特性
解释单例
怎么实现单例?
- 公有的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更有帮助性