Effective Java 读书笔记之一 创建和销毁对象
一、考虑用静态工厂方法代替构造器
这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系。相对于使用共有的构造器来创建对象,静态工厂方法有几大优势:
1、静态工厂方法有名称:通过有意义的静态工厂方法名称可以很好的表达工厂方法的作用,易于区别功能相似的多个静态工厂方法。
2、静态工厂方法可以有更复杂的生产对象逻辑,不仅仅是新建一个对象:既可以新建一个对象,也可以使用缓存的对象。
3、静态工厂方法可以返回原返回类型的任何子类型的对象:由于接口不能有静态方法,接口Type的静态工厂方法一般放在一个名为Types的工具类中。
4、静态工厂方法在在创建参数化类型实例的时候,代码更简洁:利用类型推导机制。
静态工厂方法也有一切缺陷:
1、如果类只提供静态工厂方法而不提供public或者protected的构造器,就导致该类不能被子类化了。
2、公有静态工厂方法本质上也是普通的静态工厂方法,java规范中没有对他进行特殊对待。
扩展:静态工厂方法具有一些惯用的名称:
1、valueOf——类型转换方法
2、of——类型转换方法
3、getInstance——使用参数描述返回的实例
4、newInstance——使用参数描述返回的实例,每次返回新实例
5、getType——Type表示了返回对象的类型
6、newType——Type表示了返回对象的类型,每次返回新类型
思考:静态工厂方法在java规范中,就是普通的类方法,在作用和使用方面拥有更大变动空间。构造器被java语言特殊对待,构造器的作用和功能也被java语言规范规定好了。上面列出来的四个优点和两个缺点都是从这个本质的区别推导出来的。
二、遇到多个构造器参数时要考虑用构建器
静态工厂方法和构造器有个共同的局限性:他们不能很好地扩展到大量的可选参数。当类含有多个域且有一些可选域时,解决方法有:
1、重叠构造器模式:第一个构造器只含有必选参数,后面的构造器每次增加一个可选参数。缺点:难以使用和阅读。
2、JavaBeans模式:使用无参构造器创建对象,调用setter方法设置必要的参数和可选参数。缺点:步骤繁琐,状态不一致。
3、Builder模式:使用必要参数得到一个builder对象,调用builder对象的setter方法,调用无参的build方法生产不可变的对象。缺点:性能不好,调用冗长。
思考:三种方式各有自己的优缺点:其中重叠构造器模式逻辑简单,容易掌握;JavaBeans模式较少使用,也不建议使用;Builder模式适用于参数较多且可选参数很多时。
三、用私有构造器或者枚举类型强化Singleton属性
只要是Singleton的类,其构造器一定是private的。针对Singleton的类,为使其可序列化正确,所有的实例域必须是transient的,并提供一个readResolve方法。
思考:单元素的枚举类型是实现Singleton的最佳方法。无偿提供序列化机制,绝对防止多次实例化。
四、通过私有构造器强化不可实例化的能力
通过将类做成抽象类来强制该类不可被实例化,是行不通的。通过继承该类,子类可以被实例化,从而实例化了该类。这样做是对抽象类的一种错误用法,同时误导了用户。抽象类应该是只为了继承而设计的。最好的解决方法就是现实提供私有的构造器,这样同时也使得该类不能被子类化。
思考:在确定了类的作用之后,尽量把类的构造器的权限限制到最小。
五、避免创建不必要的对象
1、构造器每次被调用都会创建一个新的对象,静态工厂方法则从来不要求这么做。尽量使用静态工厂方法。
2、除了重用不可变类的对象外,也可以重用那些已知不会被修改的可变类对象。
3、某个给定对象的特定适配器,不需要创建多个适配器实例。例如:Map接口的keySet方法每次返回相同的Set视图。
4、在Java1.5中引入了自动拆箱和装箱功能后,要注意优先使用基本类型而不是引用类型,同时要注意无意识的自动装箱。
5、小对象的创建和回收是非常廉价的,如果为了程序的清晰性、简洁性和功能性,可以不避免创建对象。只有当对象是重量级别时,维护自己的对象池才是好的做法。
六、消除过期的对象引用
1、清空对象引用是一种例外,而不是一种规范行为。在最紧凑的作用域范围内定义每一个变量是一种好的编程规范。
2、只要类是自己管理内存,程序员就应该警惕内存泄漏问题。
3、缓存是内存泄漏的另一个常见来源。WeakHashMap在缓存项的生命周期是由该键的外部引用而不是由值决定是才有用。
4、内存泄漏的第三个常见来源是监听器和其他回调。通过保存监听器和其他回调的弱应用(weak reference)可以解决此问题。
5、内存泄漏问题的发生一般比较隐蔽,需要仔细审查代码,同时结合Heap剖析工具才能发现内存泄漏的问题。
七、避免使用终结方法
1、终结方法(finalizer)通常是不可预测、也很危险和不必要的。
2、缺点一:不能保证会被及时地执行。不同的JVM上表现差异性大。执行方法的线程不确定。Java规范不保证终结方法会被执行。
3、缺点二:未被catch的异常在终结方法中的诡异行为,破坏了对象的状态,使得终结方法更加危险。
4、缺点三:终结方法有非常严重的性能损失。
如果类的对象中封装的资源确实需要终止,可以提供一个显示的终止方法。通过与try-finally结构结合起来使用,确保及时终止。具体可参考各种流对象的close方法。终止方法的缺点是需要程序员自己来显示的调用。相比之下,总结方法也有两个好处:
1、充当“安全网”,是资源释放的最后一个机会。可在其中增加日志记录,促使下一步修正此bug。
2、可用于释放不拥有关键资源的本地对等体。
注意:终结方法链不会被自动执行,需要自己在子类中调用父类的终结方法。可以通过“终结方法守卫者”模式解决此问题。
思考:除非作为安全网,或者为了终止非关键的本地资源,否则不要使用终结方法。
Effective Java 读书笔记之一 创建和销毁对象的更多相关文章
- 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器
类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...
- Effective Java 学习笔记之创建和销毁对象
一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法 ...
- Effective Java(1)-创建和销毁对象
Effective Java(1)-创建和销毁对象
- effective java 第2章-创建和销毁对象 读书笔记
背景 去年就把这本javaer必读书--effective java中文版第二版 读完了,第一遍感觉比较肤浅,今年打算开始第二遍,顺便做一下笔记,后续会持续更新. 1.考虑用静态工厂方法替代构造器 优 ...
- 《Effective Java》读书笔记 - 2.创建和销毁对象
Chapter 2 Creating and Destroying Objects item 1:Consider static factory methods instead of construc ...
- Effective Java 读书笔记之二 对于所有对象都通用的方法
尽管Object是一个具体的类,但设计它主要是为了扩展.它的所有非final方法都有明确的通用约定.任何一个类在override时,必须遵守这些通用约定. 一.覆盖equals时请遵守通用的约定 1. ...
- Effective Java——(一)创建和销毁对象
第一条 考虑用静态工厂方法代替构造器 什么叫静态工厂方法,就是通过在类中通过静态方法对对象初始化. 比如说 public class StaticFactory { private String na ...
- Effective Java(一)—— 创建和销毁对象
在客户端(调用端)获取自身实例的方法: 公有的构造器: 类的静态工厂方法: 1. 使用静态工厂方法代替构造器 Boolean 是对基本类型 boolean 的包装类: public final cla ...
- Effective Java 读书笔记(二):对象通用方法
1 重写equals方法时请遵守通用约定 (1)无需覆盖equals方法的情况 要求独一无二 不要求逻辑相等 超类已经覆盖equals方法,对其子类也适用 一个类是私有的或者是包私有(可以重写后抛出异 ...
随机推荐
- Altium Designer 15 --- Design PCB Frame by Rhinoceros
step 1: Draw a PCB shape and the main component placed in the PCB. The drawing sheet should be in th ...
- 基于WS-BPEL2.0的服务组合研究
http://tech.it168.com/soadocument/2008-01-03/200801031332376.shtml WS-BPEL是为组合Web服务而制定的一项规范.它的前身是由IB ...
- IOS中在自定义控件(非视图控制器)的视图跳转中 代理方法与代码块的比较
//代码块与代替代理的设计方法 我就以在自定义视图中(非视图控制器,不能实现视图控制功能),通过代理和代码块两种方法分别实现视图的跳转,进行对比 首先自定义了一个视图,上面有一个已经注册了得BUtto ...
- mysql常用命令之-用户密码修改
--创建用户 CREATE USER 'user1'@'localhost' IDENTIFIED BY 'pass1'; GRANT SELECT,INSERT,UPDATE,DELETE ON * ...
- js007-函数表达式
js007-函数表达式 本章内容 1.函数表达式的特征 2.使用函数实现递归 3.使用闭包定义私有量 定义函数的方式有两种:一:函数声明,二:函数表达式 函数声明: function function ...
- 使用ThreadLocal、Apache的dbutils的QueryRunner和dbcp2数据库连接池的BasicDataSource封装操作数据库工具
package hjp.smart4j.framework.helper; import hjp.smart4j.framework.util.CollectionUtil; import hjp.s ...
- MVC实现动态二级域名
前段时间,一个朋友问我ASP.NET MVC下实现动态二级域名的问题.跟他聊了一些解决方案,这里也总结一下,以供参考. 相信大家都发现类似58同城这样的网站,成都的网址是cd.58.com 上海的是s ...
- Effective Objective-C 2.0 — 第13条:用“方法调配 技术” 调试 “黑盒方法”
自己理解是调配了方法 在运行期,可以向类中新增或替换选择子所对应的方法实现. 使用另一份实现来替换原有的方法实现,这道工序叫做“方法调配”,开发者常用此技术向原有实现中添加新功能. 一般来说,只有调试 ...
- Python开发【第十一篇】:JavaScript
JavaScript是一门编程语言,浏览器内置了JavaScript语言的解释器,所以在浏览器上按照JavaScript语言的规则编写相应代码之,浏览器可以解释并做出相应的处理. 一.如何编写 1.J ...
- python sys os hashlib_MD5 模块
模块 内置模块是Python自带的功能,在使用内置模块相应的功能时,需要[先导入]再[使用] 一.sys 用于提供对Python解释器相关的操作: ? 1 2 3 4 5 6 7 8 9 sys.ar ...