Effective Java 读书笔记(一):使用静态工厂方法代替构造器
这是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 读书笔记(一):使用静态工厂方法代替构造器的更多相关文章
- 【读书笔记 - Effective Java】01. 考虑用静态工厂方法代替构造器
获取类的实例有两种方法: 1. 提供一个公有的构造器(最常用). 2. 提供一个公有的静态工厂方法(static factory method). // 静态工厂方法示例 public static ...
- effective java 3th item1:考虑静态工厂方法代替构造器
传统的方式获取一个类的实例,是通过提供一个 public 构造器.这里有技巧,每一个程序员应该记住.一个类可以对外提供一个 public 的 静态工厂方法 ,该方法只是一个朴素的静态方法,不需要有太多 ...
- 改善JAVA代码01:考虑静态工厂方法代替构造器
前言 系列文章:[传送门] 每次开始新的一本书,我都会很开心.新书新心情. 正文 静态工厂方法代替构造器 说起这个,好多可以念叨的.做了一年多的项目,慢慢也有感触. 说起构造器 大家很明白,构造器 ...
- 【Effective Java读书笔记】创建和销毁对象(一):考虑使用静态工厂方法代替构造器
类可以提供一个静态方法,返回类的一个静态实例,如Boolean包装类的一个获取实例的静态方法 public static Boolean valueOf(boolean b) { return (b ...
- Effective java读书札记第一条之 考虑用静态工厂方法取代构造器
对于类而言,为了让client获取它自身的一个实例,最经常使用的方法就是提供一个共同拥有的构造器. 另一种放你发,也应该子每一个程序猿的工具箱中占有一席之地.类能够提供一个共同拥有的静态 工厂方法.它 ...
- Effective java读书笔记
2015年进步很小,看的书也不是很多,感觉自己都要废了,2016是沉淀的一年,在这一年中要不断学习.看书,努力提升自己 计在16年要看12本书,主要涉及java基础.Spring研究.java并发.J ...
- Effective Java 读书笔记之一 创建和销毁对象
一.考虑用静态工厂方法代替构造器 这里的静态工厂方法是指类中使用public static 修饰的方法,和设计模式的工厂方法模式没有任何关系.相对于使用共有的构造器来创建对象,静态工厂方法有几大优势: ...
- Effective java 读书笔记(2)
第四条:通过私有构造器强化不可实例化的能力 有时可能需要编写只包含静态方法和静态域的类,这样的工具类不希望被实例化,因为实例化对它来说没有意义. 然而,在缺少显式构造器的情况下,系统会自动提供一个缺省 ...
- Effective Java 读书笔记
创建和销毁对象 >考虑用静态工厂方法替代构造器. 优点: ●优势在于有名称. ●不必再每次调用他们的时候都创建一个新的对象. ●可以返回原返回类型的任何子类型的对象. ●在创建参数化类型实例的时 ...
随机推荐
- 2017.7.1 nginx反向代理服务器域名解析配置(已验证可使用)
下载地址:http://learning.happymmall.com/ 前提:ftpserver已经开启,并且设置为: 1.获得安装文件 2.修改配置文件 2.1 修改conf/nginx.conf ...
- react-native 项目实战 -- 新闻客户端(3) -- 包装导航控制器
1.修改后的 Main.js /** * 主页面 */ import React, { Component } from 'react'; import { StyleSheet, Text, Vie ...
- IP数据库生成器
代码地址如下:http://www.demodashi.com/demo/12688.html 项目放在github上,python版本ipdb_creator,java版本ip-locator. 项 ...
- smali语法高亮相关链接
http://ruby-china.org/topics/8307 http://www.daqianduan.com/4820.html http://www.cnblogs.com/ruochen ...
- 使用UIDatePicker
什么是UIDatePicker 用官方文档的话来说,UIDatePicker就是使用多个滚轮来选择日期和时间的类.官方的示例有定时器,闹钟(设置时间)部件.正确设置后,UIDatePicker对象会在 ...
- Delphi Math里的基本函数,以及浮点数比较函数
Delphi里的好东西太多,多到让人觉得烦.这种感觉就是当年打游戏<英雄无敌3>,改了钱以后,有钱了每天都要造建筑,明明是好事,可是让人觉得烦. 先记录下来,以后再回来加强对Math单元的 ...
- 每日一招:如何才能在A股持续盈利?
证券市场介入门槛低,是众多普通投资者希望实现自己的“中国梦”的首选场所,无论牛市熊市,源源不断的参与者前赴后继.在沪深A股这样一个大众市场,每年都在上演着七亏两平一赚的悲喜剧,赚钱的永远是少数人,但众 ...
- 阿里云 经典网络使用ClassicLink连接到专用网络后,192.168网段需要添加路由
配置后,专用网络中的机器Ping不通经典网络, 查帮助说192.168网段需要手动添加路由表. 抓包能在经典网络中收到专用网络中过来的数据包,但回复的数据包不能正确发出去. 先用 route -n 查 ...
- 实现Nullable 可空类型
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace demo ...
- eclipse maven 依赖jar下载失败解决办法
针对PC与Maven私服之间网络传输问题 打开.m2本地仓库所在目录, 通过win文件夹的搜索功能,查找 *.lastUpdated ,然后将找到的文件全部删除 重新 Maven Update Pro ...