创建和销毁对象
No.1 考虑用静态工厂方法代替构造器
静态工厂方法的优点:
- 它们有名称
- 不必再每次调用它们的时候都创建一个新对象
- 它们可以返回原返回类型的任何子类型的对象
- 在创建参数化类型实例的时候,它们使代码变得更加简洁
静态工厂方法的缺点:
- 类如果不含公有的或者受保护的构造器,就不能被子类化
- 它们与其他的静态方法实际上没有任何区别
静态工厂方法的一些惯用名称:
- valueOf
- of
- getInstance
- newInstance
- getType
- newType
No.2 遇到多个构造器参数时要考虑用构建器
静态工厂方法和构造器都不能很好地扩展到大量的可选参数,JavaBeans模式有着严重的缺点(构造过程中可能处于不一致的状态,无法保证一致性),而Builder模式在大量可选参数的情况下可以满足可读性、一致性等要求。
总之,如果类的构造器或者静态工厂方法中具有多个参数(大于4个),设计这种类的时候,Builder模式就是不错的选择,尤其是在大多数参数是可选的时候。与传统的重叠构造器模式相比,Builder模式的客户端代码将更易于阅读和编写,构建器也比JavaBeans更加安全。
No.3 用私有构造器或者枚举类型强化Singleton属性
- 静态final域和私有构造器仍可能受到攻击
- 单元素的枚举类型已经成为实现Singleton的最佳方法。
No.4 通过私有构造器强化不可实例化的能力
工具类只有静态方法,实例化没有意义
- 企图通过将类做成抽象类来强制该类不可被实例化,这是行不通的。该类可以被子类化,并且其子类可以被实例化
- 将构造器私有化可以强化该类不可实例化的能力,但是它也使得该类不可被子类化
No.5 避免创建不必要的对象
要避免创建不必要的对象
- 如果对象是不可变的(immutable),它就始终可以被重用
- 可以通过静态工厂方法避免创建不必要的对象,比如
Boolean.valueOf(String)
- 重用那些已知不会被修改的对象
- 优先使用基本类型而不是装箱基本类型,当心无意识的自动装箱
- 小对象的创建和回收动作是廉价的,所以不能绝对化的认为要避免创建对象,通过创建附加对象,提升程序的清晰性、简洁性和功能性,这通常是好事
实践:
- 比如
String str= new String("test");
就是很不好的例子,应该使用String str= "test";
- 字符串的多次拼接应该考虑使用
StringBuilder
而不是简单的+
或者+=
,除非只是一次性的拼接(编译器会自动优化)
No.6 消除过期的对象引用
- 清空对象引用应该是一种例外,而不是一种规范行为
- 只要类是自己管理内存,程序员就应该警惕内存泄漏问题
- 内存泄漏的另一个常见来源是缓存
- 内存泄漏的第三个常见来源是监听器和其他回调
- 最好能在内存泄漏发生之前就知道如何预测此类问题,并阻止它们发生
解决方案:
- 使用弱引用
WeakHashMap
- 后台线程定期清理没用的缓存项,比如
LinkedHashMap
的removeEldestEntry
- 对于更加复杂的缓存,必须直接使用
java.lang.ref
No.7 避免使用终结方法
- 终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的
- 不应该依赖终结方法来更新重要的持久状态,因为不保证终结方法会被执行
- 使用终结方法有一个非常严重的(Severe)性能损失
- 最好使用显式终结方法,通常与
try...finally
结构结合起来使用,以确保及时终止。比如InputStream
、OutputStream
和java.sql.Connection
用途:
- 终结方法可以充当“安全网(safety net)“,在客户端为进行显式终止来正常结束的情况下释放资源,但是如果终结方法发现资源还未被终止,则应该在日志中记录这一警告,比如
FileInputStream
- 第二个用途与对象的本地对等体(native peer)有关,终结方法应该完成所有必要的工作,释放关键的资源
注意:
- 如果子类覆盖了超类的终结方法,但是忘了手动调用超类的终结方法,那么超类的终结方法将永远的不到调用
- 可以将终结方法放在一个匿名的类中,它的唯一用途就是终结外围实例(enclosing instance),被称为终结方法守卫者(finalizer guardian)