之前在工作学习中,总是觉得能解决问题就好了,到后来发现其实这只是第一步,能解决之后还应该思考怎么做更优雅,更合理。但是总没有一个标准的说法,网上也常常众说纷纭,最近在阅读《Effective Java》发现提供了不少使用Java语言开发上的最佳实践,我觉得这当然不是让人学习死的模版代码,更是让人学习为何这样就好,是学习这种开发思想。
本篇是学习《Effective Java》的第二章总结,对象的创建和销毁的实践。
简介
本片包含的内容:
- 对象的创建:
- 考虑用静态工厂方法代替构造器
- 遇到多个构造参数时考虑用构造器
- 用私有构造器或枚举强化Singleton属性
- 通过私有构造器强化不可实例的能力
- 避免创建不必要的对象
- 对象的销毁:
- 消除过期的对象引用
- 避免使用终结(finalize)方法
下面就总结这每一条建议。
对象的创建
先来看看对象创建中的建议~
1、考虑用静态工厂方法代替构造器
使用构造方法可以创建对象,静态方法中包含构造方法的调用也可以创建对象,那么后者具有哪些优势呢?(注:下文的默认主语是静态工厂方法)
- 名称具有意义:更能让使用者明白;
- 不必在每次调用时都创建对象:可重复利用对象,提高性能;
- 可以返回原返回类型的任何子类型:实现更加灵活,可减少API的数量,提高可阅读性和可维护性(返回对象可随版本的变更而改变);
- 在创建参数化类型实例时,可简化代码自动推倒类型;(1.7之后jdk支持泛型实例化类型自动推倒)
当然也存在不好的地方:
- 如果类没有公有或受保护的构造器,就不能被子类化:但是正好,因为推荐多使用复合;
- 与其他静态方法没有区别:所以想要查明哪一个是用于创建对象的不容易找到,当然可以使用一些习惯的编码方式约定一下。例如:newInstance(…)这样。
2、遇到多个构造参数时要考虑用构建器
说构建器可能不那么通俗易懂,如果说Builder模式可能就很多人都知道了,如果参数的数量多于4个的或者是以后可能会继续添加参数的时候,就可以选择使用Builder模式。
它可以在build的时候检查某些参数是否传入,也能自动默认设置某些值,相对于传统的构造函数也更易于阅读。
但是这种模式要创建对象就得先有一个Builder,增加一点性能的开销,所以在特别注重性能的情况就应该根据实际情况自行选择。
3、用私有构造器或枚举强化Singleton属性
单例模式有两种方式,第一种是使用类时将构造函数私有化,并且在内部创建一个实例且是公有的或公有方法可获取到的;第二种方式是使用jdk1.5之后新增的枚举类型,只含有一个枚举实例即可,这也是目前最佳的实现方法。
4、通过私有构造器强化不可实例化的能力
对于某些不想被实例化的类来说,若不提供构造函数则系统会默认提供无参构造函数,所以需要将构造函数私有化才能避免,并加上注释说明为何要私有化。当然也不要将类作为抽象类,因为这样子类依然能实例化,而且这样会让使用者误会。
5、避免创建不必要的对象
对于不可变且会多次用到的对象都可以缓存起来避免重复创建;对于基本类型和装箱基本类型尽量优先使用基本类型,并且不要混合使用。对于自己维护一个对象池往往是不值得的,除非对象的创建的代价非常昂贵,例如数据库的连接。
对象的销毁
6、消除过期的对象引用
若过期的对象未被销毁则会导致内存泄漏(无意识的对象保持),内存不断增加,导致系统性能下降,并可能导致OOM。需要注意的是:若是类自己去管理内存,就应该小心内存泄漏,也就是说如果类的字段中包含其他类,就应该注意内存泄漏,常见的就是将这个类缓存起来;当然监听器以及回调也常常会导致内存泄漏,解决办法就是使用弱引用保存这些监听器或回调。
7、避免使用终结(finalize)方法
finalizer方法通常是不知道会在什么时候被调用,而且会增加对象创建和销毁的时间,应该避免使用,除非是作为安全网或者终止非关键的本地资源。但是这些情况都比较少见,所以尽量不要用到这个方法去改变状态,可以使用try-finally去代替。
总结
对象的创建和销毁是开发中最常见的,合理的创建和销毁对象能提高程序的效率,这也就是学习这一章的目的吧~