这是Effective Java第2章提出的第一条建议:

考虑用静态工厂方法代替构造器

此处的静态工厂方法并不是设计模式,主要指static修饰的静态方法,关于static的说明可以参考之前的博文《java中final与static的使用场景总结》

什么是静态工厂方法?

可以参考书中的例子(摘自JDK1.7 java.lang.Boolean)

public final class Boolean implements java.io.Serializable,
Comparable<Boolean> { public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false); public static Boolean valueOf(boolean b) {
return (b ? TRUE : FALSE);
}
}

如果需要获取一个Boolean对象,常规的方法是new Boolean(true),但是也可以如上图所示Boolean.valueOf(true),这便是静态工厂方法。

静态工厂方法的优势

静态工厂方法与构造器不同的第一大优势在于,它们有名称

使用构造函数构造对象时,我们需要通过文档仔细比对传递什么样的参数能够构造什么样的对象。但是静态工厂方法可以使用不同的方法名字使得其构造的对象更加明晰。我们完全可以通过方法名明白构造了什么样的对象。

例如下面的例子(摘自JDK1.7 java.math.BigInteger)

public class BigInteger extends Number implements Comparable<BigInteger> {
/**
* Returns a positive BigInteger that is probably prime, with the
* specified bitLength. The probability that a BigInteger returned
* by this method is composite does not exceed 2<sup>-100</sup>.
*/
public static BigInteger probablePrime(int bitLength, Random rnd) {
// XXX
}
}

静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候都创建一个新对象

我们调用静态工厂方法返回的可能是缓存的一个对象,而不是新对象。可以进行重复利用,从而避免创建不必要的重复对象。 
如果程序经常请求创建相同的对象,并且创建的代价很高,则静态工厂方法可以极大地提升性能。 
前面提到的Boolean.valueOf(boolean)便说明了这项技术。

静态工厂方法与构造器不同的第三大优势在于,他们可以返回原返回类型的任何子类型的对象。

我们在选择返回对象的类时有了更大的灵活性。参见java.util.EnumSet,其本身被abstract修饰,无法直接调用其构造函数。但可以调用其静态方法noneOf来创建对象,并且根据参数返回合适的对象。

public abstract class EnumSet<E extends Enum<E>> extends AbstractSet<E>
implements Cloneable, java.io.Serializable { EnumSet(Class<E>elementType, Enum[] universe) {
}
//RegularEnumSet与JumboEnumSet均为EnumSet的子类
public static <E extends Enum<E>> EnumSet<E> noneOf(Class<E> elementType) {
if (universe.length <= 64)
return new RegularEnumSet<>(elementType, universe);
else
return new JumboEnumSet<>(elementType, universe);
}
}

第四大优势在于,创建参数化类型实例的时候,可以使代码变得更加简洁。

例如对于HashMap的实例化:

//常规实例化方式
Map<String, List<String>> m =
new HashMap<String, List<String>>(); public static <K, V> HashMap<K, V> newInstance() {
return new HashMap<K, V>();
}
//使用静态工厂方法实例化,简化繁琐的声明
Map<String, List<String>> m = HashMap.newInstance();

静态工厂方法的劣势

类如果不含公有的或受保护的构造器,就不能被实例化。

如果我们在类中将构造函数设为private,只提供静态工厂方法来构建对象,那么我们将不能通过继承扩展该类。 
但是这也会鼓励我们使用复合而不是继承来扩展类。

它们与其他的静态方法实际上没有任何区别。

在API文档中,构建对象的静态工厂方法并没有像构造器那样明确标识出来,不能和其他静态方法很方便地区分开来。 
如果类中只提供静态工厂方法而不是构造器,要想查明如何实例化一个类将会变得困难。 
我们可以通过遵循静态工厂方法的命名规范来弥补这一劣势:

  • valueOf - 返回的实例与它的参数具有相同的值,一般作为类型转换使用,例如Boolean.valueOf(boolean)
  • of - valueOf的更为简洁的替代。
  • getInstance - 返回的实例通过方法的参数来描述,但不能说与参数具有同样的值。对于Singleton来说,使用无参getInstance,返回唯一的实例。
  • newInstance - 像getInstance一样,但其能够确保每次都返回新的对象。
  • getType - 像getInstance一样,但此方法返回的对象是另一个不同的类。
  • newType - 像getType一样,但每次返回一个新对象。

总而言之,静态工厂方法和公有构造器具有各自的用处,但静态工厂方法通常更加合适,所以我们应该优先考虑静态工厂方法。

Effective Java 读书笔记(一):使用静态工厂方法代替构造器的更多相关文章

  1. 【读书笔记 - Effective Java】01. 考虑用静态工厂方法代替构造器

    获取类的实例有两种方法: 1. 提供一个公有的构造器(最常用). 2. 提供一个公有的静态工厂方法(static factory method). // 静态工厂方法示例 public static ...

  2. effective java 3th item1:考虑静态工厂方法代替构造器

    传统的方式获取一个类的实例,是通过提供一个 public 构造器.这里有技巧,每一个程序员应该记住.一个类可以对外提供一个 public 的 静态工厂方法 ,该方法只是一个朴素的静态方法,不需要有太多 ...

  3. 改善JAVA代码01:考虑静态工厂方法代替构造器

    前言 系列文章:[传送门]   每次开始新的一本书,我都会很开心.新书新心情. 正文 静态工厂方法代替构造器 说起这个,好多可以念叨的.做了一年多的项目,慢慢也有感触. 说起构造器 大家很明白,构造器 ...

  4. 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器

    类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...

  5. Effective java读书札记第一条之 考虑用静态工厂方法取代构造器

    对于类而言,为了让client获取它自身的一个实例,最经常使用的方法就是提供一个共同拥有的构造器. 另一种放你发,也应该子每一个程序猿的工具箱中占有一席之地.类能够提供一个共同拥有的静态 工厂方法.它 ...

  6. Effective java读书笔记

    2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...

  7. Effective Java 读书笔记之一 创建和销毁对象

    一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...

  8. Effective java 读书笔记(2)

    第四条:通过私有构造器强化不可实例化的能力 有时可能需要编写只包含静态方法和静态域的类,这样的工具类不希望被实例化,因为实例化对它来说没有意义. 然而,在缺少显式构造器的情况下,系统会自动提供一个缺省 ...

  9. Effective Java 读书笔记

    创建和销毁对象 >考虑用静态工厂方法替代构造器. 优点: ●优势在于有名称. ●不必再每次调用他们的时候都创建一个新的对象. ●可以返回原返回类型的任何子类型的对象. ●在创建参数化类型实例的时 ...

随机推荐

  1. 2017.4.18 静态代码分析工具sonarqube+sonar-runner的安装配置及使用

    配置成功后的代码分析页面: 可以看到对复杂度.语法使用.重复度等等都做了分析,具体到了每一个方法和每一句代码. 四种使用方式: sonarqube + sonar-runner sonarqube + ...

  2. EffectiveJava(6)消除过期对象的引用

    消除过期对象的引用 过期引用 – 在操作集合类的时候,未清理过期的对象引用(即:过期引用),常会导致内存泄露.从而报outOfmemory错误. 1.过期对象导致内存泄漏. 2.一旦对象引用过期,清除 ...

  3. Web 目录枚举与遍历漏洞解决

    "目录枚举漏洞"解决方法 一.名词解释 网站目录枚举漏洞:指黑客利用非法攻击手段扫描符合"8.3"命名原则的目录与文件. 二.验证工具:scanner-comp ...

  4. hibernate学习系列-----(2)hibernate核心接口和工作机制

    在上一篇文章hibernate学习系列-----(1)开发环境搭建中,大致总结了hibernate的开发环境的搭建步骤,今天,我们继续了解有关hibernate的知识,先说说这篇文章的主要内容吧: C ...

  5. redmine安装笔记

    切换到redmine安装目录 对所有ip开放启动命令,并且注册为后台运行 nohup ruby bin/rails server webrick -e production -b 0.0.0.0 -p ...

  6. GMGC记实(上篇)

    24日和25日參加了2014年GMGC大会,整体感觉今年的大会比前2届大会办的更符合听众的需求.由于今年的大会开设了开发人员训练营的分会场.在成都这样一个CP占主流的IT圈中非常有意义.另一点就是在会 ...

  7. Servlet的API(一)

    Servlet的API有很多,这里只谈谈两个Servlet对象:ServletConfig对象和ServletContext对象. 1. ServletConfig对象 在Servlet的配置文件中, ...

  8. 跨discuz站获取

    1.在需要取得formhash的页面加入下面js代码,还需要jquery库. <script lanuage="javascript"> $(function(){ $ ...

  9. MQTT--Mosquitto的配置文件

    Mosquitto的配置文件存放在/etc/mosquitto/mosquitto.conf 配置文件具体的配置内容为: # ===================================== ...

  10. memcache和memcached区别

    Memcache是一个自由和开放源代码.高性能.分配的内存对象缓存系统.用于加速动态web应用程序,减轻数据库负载.它可以应对任意多个连接,使用非阻塞的网络IO.由于它的工作机制是在内存中开辟一块空间 ...