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、可用于释放不拥有关键资源的本地对等体。

  注意:终结方法链不会被自动执行,需要自己在子类中调用父类的终结方法。可以通过“终结方法守卫者”模式解决此问题。

  思考:除非作为安全网,或者为了终止非关键的本地资源,否则不要使用终结方法。

 

时间: 2024-08-09 19:52:41

Effective Java 读书笔记之一 创建和销毁对象的相关文章

Effective Java 读书笔记(2创建和销毁对象)

第一章是引言,所以这里不做笔记,总结一下书中第一章的主要内容是向我们解释了这本书所做的事情:指导Java程序员如何编写出清晰.正确.可用.健壮.灵活和可维护的程序. 2.1考虑用静态工厂方法代替构造器 静态工厂方法与构造器相比有四大优势: (1)静态工厂方法有名称,具有适当名称的静态工厂方法易于使用.易于阅读: (2)不必每次在调用它们的时候都创建一个新的对象: (3)可以返回原返回类型的任何子类型的对象: (4)在创建参数化类型实例的时候,它们使代码变得更加简洁. 同时静态工厂方法也有两大缺点

effective java读书笔记1——创建和销毁对象

今天刚开始读effective java,中文版的读起来很拗口,但感觉收获很多. 另外,这本书的内容是针对Java 1.5和1.6的. 在这里整理一下第2章:创建和销毁对象 的内容. 第一条:考虑用静态工厂方法代替构造器 这一条针对的情景是要获得类的实例时.一般说来,想要获得类的实例,都是通过构造函数(书里叫做构造器). 最常见的构造函数是这样的,没有返回参数,名字和类名相同. public class A{ public A(int a){ //构造函数内容 ... } } 而所谓的静态工厂,

Effective Java 学习笔记之创建和销毁对象

一.考虑用静态工厂方法代替构造器 1.此处的静态工厂方法是指返回指为类的对象的静态方法,而不是设计模式中的静态工厂方法. 2.静态工厂方法的优势有: a.使用不同的方法名称可显著地表明两个静态工厂方法的不同,而不像构造器,名字只能是类名. b.并不是每次调用静态工厂方法,都会重新构造一个新的对象. c.可以返回类型的子类型的对象. d.创建参数化类型的实例时,代码变得简洁了. 3.静态工厂方法的缺点有: a.类如果不含有公有的或者受保护的构造器,就不能被子类化(静态工厂方法的存在导致构造器存在的

Effective Java 读书笔记之二 对于所有对象都通用的方法

尽管Object是一个具体的类,但设计它主要是为了扩展.它的所有非final方法都有明确的通用约定.任何一个类在override时,必须遵守这些通用约定. 一.覆盖equals时请遵守通用的约定 1.Object中默认的equals方法约定是:类的每个实例都只与它自身相等.当类有自己特有的“逻辑相等”的概念时,就应该覆盖equals方法. 2.Timestamp对Date进行了扩展,Timestamp的equals实现确实违反了对称性.如果Timestamp和Date混合一起使用,可能导致不正确

Effective Java(1)-创建和销毁对象

原文地址:https://www.cnblogs.com/Johar/p/10556218.html

Effective Java读书笔记(4 类和接口)

4.1 使类和成员的可访问性最小化 要区别设计良好的模块和设计不好的模块,最重要的因素在于,这个模块对于外部的其他模块而言,是否隐藏其内部数据和其他实现细节.设计良好的模块会隐藏所有的实现细节,把它的API与它的实现清晰的隔离开来,然后模块之间只通过API进行通信,一个模块不需要知道其他模块内部的工作情况,这个概念被称为信息隐藏或封装,是软件设计的基本原则之一. 4.2 在公有类中使用访问方法而非公有域 坚持面向对象程序设计思想:如果类可以在它所在的包的外部进行访问,就提供访问方法,以保留将来改

Effective Java读书笔记(3对于所有对象都通用的方法)

3.1 覆盖equals时请遵守通用约定 什么时候应该覆盖Object.equals()方法呢? 如果类具有自己特有的"逻辑相等"概念(不同于对象等同的概念),而且超类还没有覆盖equals以实现期望的行为,这时我们就需要覆盖equals方法. Object.equals()方法具有自反性.对称性.传递性.一致性和与null比较返回false的特点. 实现高质量equals方法的诀窍: (1)使用==操作符检查"参数是否为这个对象的引用".如果是,则返回true,这

Effective C++读书笔记之十三:以对象管理资源

Item 13:Use objects to manage resources 假设我们使用一个用来塑膜投资行为的程序库,其中各式各样的投资类型继承自一个root class: class Investment { ... };  //"投资类型"继承体系中的root class 进一步假设,这个程序系通过一个工厂函数(工厂函数会"返回一个base class指针,指向新生成的derived class 对象),供应我们某特定的Investment对象: Investment

[Effective Java 读书笔记] 第二章 创建和销毁对象 第一条

第二章  创建和销毁对象 第一条 使用静态工厂方法替代构造器,原因: 静态工厂方法可以有不同的名字,也就是说,构造器只能通过参数的不同来区分不同的目的,静态工厂在名字上就能表达不同的目的 静态工厂方法不用每次调用的时候都创建新的对象(其实是因为它是static的,所以只能用static的,所以是一早就创建了,不需要重复创建吧..),比如书中 Boolean.valueOf(boolean) 1 public static final Boolean TRUE = new Boolean(true