Effective Java阅读笔记——创建和销毁对象(一)

  类通常提供一个公有的构造器方法,以此来让客户端可以获取自己(类)的一个实例。但是在创建对象时,应该首先考虑利用静态工厂方法代替构造器来返回一个实例。利用静态工厂方法而不是公有的构造器有几个优势:

静态工厂方法有(不同的)名字

  构造器方法都有相同的名字,就是类的名字。区分不同构造器的方法是通过观察方法的签名确定的。方法的签名包括方法名,方法参数的类型,数目以及顺序,方法的返回类型不是方法签名的一部分。无法通过构造器方法名区分不同的构造器,只能通过参数的不同区分,这种情况下(特殊情况下有可能参数类型和数目相同但是顺序不同,此时也是不同的构造器方法)往往不能明显的区分不同的构造器方法的作用,不太直观造成难以理解的情况。而静态工厂方法可以使用不同的名字,直观易于理解。

  例如:BigInteger(int,int,Random)构造器方法可能返回素数,可以使用一个静态工厂方法来返回一个实例:BigInteger.probablePrime,这样更加清楚直观。

静态工厂方法不必在每次调用时都创建一个新对象

  很多情况下,每次调用工厂方法都需要同样的实例,因此可以使用预先构建好的实例或者将构建好的实例缓存起来,进行重复利用。这样就不用每次重新构建新的实例,节省空间和时间。类似于String,基本类型的包装类,BigInteger,BigDecimal这样的不可变类,一旦创建这些类的实例,实例就不会改变。这种不可变类就适用于这种情况。

静态工厂方法可以返回原返回类型的任何子类型的对象

  利用构造器方法构建实例(使用new操作符)时,只能返回类本身的实例。而使用静态工厂方法可以返回子类型的对象,大大增加了灵活性。

  举例来说,java 1.5中引入的java.util.EnumSet类没有公有构造器,只有静态工厂方法。EnumSet有两种实现类,分别是RegalarEnumSet和JumoboEnumSet两种。具体返回哪种实现类取决于静态工厂方法的参数,当底层枚举类型元素有64或者更少时使用RegalarEnumSet实现,大于等于65时使用JumoboEnumSet实现。这两种实现都不需要是公有(public)类,从而隐藏了具体的实现。可以继续增加或者减少实现类的数目,从而灵活性大大增加,类用户不必再关注于实现细节。

  除了上面所举的子类外,还有一种类似的面向接口的编程思想。静态工厂方法返回类型可以限定为接口,具体的返回对象只要满足接口就可以。具体而已,返回对象可以之要求满足List<T>,实际的返回类型可以是ArrayList<T>,LinkedList<T>等实现了List接口的类型即可。用户只需要关注于接口。

  静态工厂方法返回的对象所属的类在编写静态工厂方法时可以不存在,这种灵活性是服务提供者框架(service provider framework)的基础。JDBC是一个服务提供者框架。

静态工厂方法在创建参数化类型实例的时候,可以使代码更简洁(旧版本)

在创建参数化类(范型类)的实例时,在低版本的情况下,即使类型参数很明显,也必须指明类型。例如:

Map<String,List<String>> m=new HashMap<String,List<String>>();

在使用静态工厂方法的情况下,编译器可以直接进行类型推导,从而省去指明类型参数的情况。静态工厂方法为:

  public static <K,V> HashMap<K,V> newInstance(){ return new HashMap<K,V>();       }

ps:高版本的java中在直接调用构造器是已经不需要指明类型参数了,这里只是做个读书笔记!!!同时明确静态工厂方法这种情况下可以进行类型推导。

使用静态工厂方法相对于直接调用构造器方法也有缺点:

  缺点一:类如果不含有公有的或者受保护的构造器,就没法被继承。

  缺点二:静态工厂方法只是不同的静态方法,不是特殊的机制。因此有可能造成用户的困惑,有可能使用户产生迷惑,不清楚类如何实例化。但是有几个通用的规范可以帮助用户,静态工厂方法有一些惯用名称,如valueOf,of,getInstance,newInstance,getType,newType。

  总而言之,构造器和静态工厂方法都各有好处。

时间: 2024-12-09 19:50:46

Effective Java阅读笔记——创建和销毁对象(一)的相关文章

[Effective Java]第二章 创建和销毁对象

第一章      前言 略... 第二章      创建和销毁对象 1.            考虑用静态工厂方法代替构造器 创建对象方法:一是最常用的公有构造器,二是静态工厂方法.下面是一个Boolean的简单示例: public static Boolean valueOf(boolean b) { return (b ? Boolean.TRUE : Boolean.FALSE); } l  静态工厂方法与构造器不同的第一大优势在于,它们有名称. 作用不同的公有构造器只能通过参数来区别(因

Effective java 第二章创建和销毁对象 读书笔记

建和销毁对象 一般有两种方式,一种是获得本身的实例,最常用的方法就是提供一个共有的构造器.第二个方法是,类可以提供一个共有的静态工厂方法. 静态工厂方法与构造器不同的三大优势: 有名字: 调用时不用创建新的对象: 返回原来类型的任何子类型对象. 第四大优势: 在创建参数化类型实例的时候,它们使代码变得更加简洁. 服务提供者框架 三个组件: 服务接口 提供者主持API 服务访问API 可选: 服务提供者接口 静态工厂方法的缺点: 类如果不含共有的或者受保护的构造器,就不能被子类化: 它们与其他的静

Effective java经验之谈,创建和销毁对象

关于Effective java 这本书,自己的一些总结性的思考.篇幅可能不按照目录来,因为自己喜欢先看哪一章就直接阅读了.不过能确定的是,每一章都会有总结.欢迎大家拍砖与补充. 1.      考虑用静态工厂的方法代替构造器.优点:有名字,不必每次创建对象,返回任何子类型对象,简洁的代码.缺点:该类将不能被子类化(复合大于继承,也是优点),不方便doc工具输出文档,一般约定的命名规则: valueOf  转换类型 getInstance 获得对象实例 newInstance 创建新的对象实例

Effective Java2读书笔记-创建和销毁对象(一)

第1条:考虑用静态工厂方法代替构造器 通常情况下,我们创建一个对象采取new的形式,但是还有一种方法也是经常使用到的,它的名称叫做静态工厂方法. 例如,java中基本类型boolean的包装类Boolean就采用了这种方式,源代码如下: public static Boolean valueOf(boolean b) { return (b ? TRUE : FALSE); } 当然,除了valueOf这种比较low的名字之外,我们常用的还有getInstance(最常见),newInstanc

Effective Java2读书笔记-创建和销毁对象(三)

第5条:避免创建不必要的对象 本条主要讲的是一些反面教材,希望大家引以为鉴. ①无意中使用自动装箱导致多创建对象. public class Sum { public static void main(String[] args) { Long sum = 0L; for (long i = 0; i < Integer.MAX_VALUE; i++) { sum += i; } System.out.println(sum); } } sum被声明为Long而不是long,意味着每次i都要被自

Effective Java2读书笔记-创建和销毁对象(四)

第7条:避免使用终结方法 这一条讲的简直是不知所云.先简单记下来其中说出的几条: ①显式终止方法的典型例子有InputStream.OutputStream和java.sql.Connection上的close方法,以及java.util.Timer上的cancel方法.这些方法一般与try-catch连用,在finally中调用显式的终止方法.终结方法的意义在于这些close方法忘记调用时,充当安全网的作用(感觉扯淡,close都会忘,终结方法能记得?). ②finalize方法,源自Obje

Effective Java2读书笔记-创建和销毁对象(二)

第3条:用私有构造器或者枚举类型强化Singleton属性 这一条,总体来说,就是讲了一个小技巧,将构造器声明为private,可以实现单例.具体有以下几种实现的方式. ①最传统的单例实现模式,可能有很多变种,核心思想是私有化构造器. public class Singleton { private static final Singleton INSTANCE = new Singleton(); private Singleton(){}; public static Singleton g

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

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

Effective Java 阅读笔记——方法

38:检查参数的有效性 每当编写方法或者构造器的时候,应该考虑它的参数有哪些限制,在方法的开头处对参数进行检查,并且把这些限制写入文档. 注意: 对于公有方法,应该使用@throws标签在文档中说明违反参数值限制会抛出的异常 对于非公有的方法,通常使用断言来检查他们的参数:断言如果失败,抛出AssertionError:如果没有起到作用,本质上也不会有成本开销 private void sort(long a[]){ assert a != null; } 对于构造函数中的,或者参数将会被保存,