Chapter 01:创建和销毁对象
《一》考虑用静态工厂方法代替构造器
下面是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);
}
}
Why ?平时我们用共有的构造器不爽吗?
1.静态工厂方法与构造器不同的第一大优势在于,它们有名称!!!名称对于程序多重要,毋庸置疑了,如果你没这样感觉,那就什么都别说,多敲代码就知道了。
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) {
}
}
2.静态工厂方法与构造器不同的第二大优势在于,不必在每次调用它们的时候创建一个新的对象。比如不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用,从而达到提升性能的效果。
3.静态工厂方法与构造器不同的第三大优势在于,它们可以返回原返回类型的任何子类型的对象。这样在选择返回对象上就有了更大的灵活性。
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);
}
}
4.静态工厂方法的第四大优势在于,在创建参数化类型实例的时候,它们使代码变得更加简洁。
//常规实例化方式
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();
Not? 利弊总是同时存在,没有尽善尽美的东西
1.静态工厂的方法的主要缺点在于,类如果不含公有的或者受保护的构造器,就不能子类化。
如果我们在类中将构造函数设为private,只提供静态工厂方法来构建对象,那么我们将不能通过继承扩展该类。
但是这也会鼓励我们使用复合而不是继承来扩展类。
2.静态工厂方法的第二缺点在于,它们与其他静态方法实际没有任何区别。
在API文档中,构建对象的静态工厂方法并没有像构造器那样明确标识出来,不能和其他静态方法很方便地区分开来。
可以通过遵循静态工厂方法的命名规范来弥补这一劣势:
- valueOf - 不太严格的讲,该方法返回的实例与它的参数具有相同的值,一般作为类型转换使用
- of - valueOf的更为简洁的替代。
- getInstance - 返回的实例通过方法的参数来描述,但不能说与参数具有同样的值。对于Singleton来说,使用无参getInstance,返回唯一的实例。
- newInstance - 像getInstance一样,但其能够确保每次都返回新的对象。
- getType - 像getInstance一样,但此方法返回的对象是另一个不同的类。
- newType - 像getType一样,但每次返回一个新对象。
总而言之,静态工厂方法和公有构造器具有各自的用处,但静态工厂方法通常更加合适,因此切记第一反应就是提供公有的构造器,而先不考虑静态工厂方法。
《二》遇到多个构造器参数时候要考虑构建器
遇到多个构造器参数,一般采用的是重叠构造器模式,或者JavaBeans模式(线程不安全)
这里要说的是第三种,既能像重叠构造器模式那样安全性,也能保证像JavaBeans模式那么好的可读性,这就是Builder模式,构建器模式。
eg:
// Builder Pattern - Pages 14-15 public class NutritionFacts {
private final int servingSize;
private final int servings;
private final int calories;
private final int fat;
private final int sodium;
private final int carbohydrate; public static class Builder {
// Required parameters
private final int servingSize;
private final int servings; // Optional parameters - initialized to default values
private int calories = 0;
private int fat = 0;
private int carbohydrate = 0;
private int sodium = 0; public Builder(int servingSize, int servings) {
this.servingSize = servingSize;
this.servings = servings;
} public Builder calories(int val)
{ calories = val; return this; }
public Builder fat(int val)
{ fat = val; return this; }
public Builder carbohydrate(int val)
{ carbohydrate = val; return this; }
public Builder sodium(int val)
{ sodium = val; return this; } public NutritionFacts build() {
return new NutritionFacts(this);
}
} private NutritionFacts(Builder builder) {
servingSize = builder.servingSize;
servings = builder.servings;
calories = builder.calories;
fat = builder.fat;
sodium = builder.sodium;
carbohydrate = builder.carbohydrate;
} public static void main(String[] args) {
NutritionFacts cocaCola = new NutritionFacts.Builder(240, 8).
calories(100).sodium(35).carbohydrate(27).build();
}
}
Java传统抽象工厂实现是class对象,用newInstance方法充当build方法的一部分,这种用法隐含许多问题,因为newInstance总是企图调用类的无参构造,这个构造可能根本不存在,但是也不会收到编译时期错误,相反,必须在运行时处理,换句话说,Class.newInstance破坏了编译时期的异常检查。
Builder模式不足之处,为了创建对象必须先创建它的构造器,虽然创建构造器的开销,实际中可以忽略,注重性能的情况除外,同时他比其他模式更加冗余。
因此,只有在参数比较多的时候使用它才比较合理(一般参数4个+),切记,一开始使用重叠构造或者JavaBeans,中间再切换构造器,这样会导致代码不协调,很乱,最好计划一开始就用。简而言之,如果类的构造器或者静态工厂中具有多个参数,设计这种类时候,Builder是不错选择,特别当大多数参数都是可选的,这样会使代码更加容易阅读和编写,同时也比JavaBeans更安全。
Chapter 01:创建和销毁对象的更多相关文章
- Effective Java笔记一 创建和销毁对象
Effective Java笔记一 创建和销毁对象 第1条 考虑用静态工厂方法代替构造器 第2条 遇到多个构造器参数时要考虑用构建器 第3条 用私有构造器或者枚举类型强化Singleton属性 第4条 ...
- 《Effective Java》—— 创建与销毁对象
本篇主要总结的是<Effecticve Java>中关于创建和销毁对象的内容. 比如: 何时以及如何创建对象 何时以及如何避免创建对象 如何确保及时销毁 如何管理对象销毁前的清理动作 考虑 ...
- ch2 创建和销毁对象
ch2 创建和销毁对象
- [Effective Java]第二章 创建和销毁对象
声明:原创作品,转载时请注明文章来自SAP师太技术博客( 博/客/园www.cnblogs.com):www.cnblogs.com/jiangzhengjun,并以超链接形式标明文章原始出处,否则将 ...
- 《Effect Java》学习笔记1———创建和销毁对象
第二章 创建和销毁对象 1.考虑用静态工厂方法代替构造器 四大优势: i. 有名称 ii. 不必在每次调用它们的时候都创建一个新的对象: iii. 可以返回原返回类型的任何子类型的对象: JDBC ...
- effective java读书小记(一)创建和销毁对象
序言 <effective java>可谓是java学习者心中的一本绝对不能不拜读的好书,她对于目标读者(有一点编程基础和开发经验)的人来说,由浅入深,言简意赅.每一章节都分为若干的条目, ...
- 和我一起学Effective Java之创建和销毁对象
前言 主要学习创建和销毁对象: 1.何时以及如何创建对象 2.何时以及如何避免创建对象 3.如何确保它们能够适时地销毁 4.如何管理对象销毁之前必须进行的清理动作 正文 一.用静态工厂方法代替构造器 ...
- Effective Java(1)-创建和销毁对象
Effective Java(1)-创建和销毁对象
- 《Effective Java 2nd》第2章 创建和销毁对象
目录 第1条:考虑使用静态工厂方法代替构造器 第2条:遇到多个构造器参数时考虑用构建器 第3条:用私有构造器或者枚举类型强化Singleton属性 第4条:通过私有构造器强化不可实例化的能力 第5条: ...
- 《Effective Java》读书笔记(一)之创建和销毁对象
最近在研读<Effective Java>一书,读书不做点笔记,感觉很容易就忘掉,于是用本篇博客来记录阅读此书的笔记. 郑重声明: 由于是<Effective Java>一书的 ...
随机推荐
- UVA11401Triangle Counting(简单计数)
转载请注明出处: http://www.cnblogs.com/fraud/ ——by fraud 题目意思:从1,2,3,……,n中选出3个不同的整数使其构成一个三角形,有多少种方 ...
- 在word中使用notepad++实现代码的语法高亮
转载自:http://blog.csdn.net/woohello/article/details/7621651 有时写文档时需要将代码粘贴到word中,但直接粘贴到word中的代码虽能保持换行与缩 ...
- mysql 关键字bug
今天运行语句 select * from order; 出现bug: ERROR 1064 (42000): You have an error in your SQL syntax; check t ...
- Linux上使用Azure CLI来管理Azure
在Windows上我们有强大的Powershell提供各种命令来管理Azure的服务,在Linux上微软提供了基于Node.JS的跨平台的Azure Command Line来帮助Linux用户来管理 ...
- NOI十连测 第六测 T1
思路: 用treap动态维护,记一个sum1,sum2,注意!,写treap如果有删除操作,千万不能把权值相同的分开来..,这在删除的时候会进入死循环,这是一个惨痛的教训... #include< ...
- USB系列之四:向U盘上写数据
在<USB系列之三>中,我们实现了一系列的SCSI命令,在这个系列中,我们要实现向U盘上写扇区的命令,所以,本文相对比较容易,更多地是给出一个实现的源程序. 在<USB系列之三> ...
- FileAccess枚举
FileAccess用于控制对文件的读访问.写访问或读/写访问的常熟.从源代码可以看到FileAccess是一个简单枚举. 枚举成员 成员值 描述 Read 1 对文件的读访问,拥有读取权限. Wri ...
- 使用 asp.net Web API 2的坑
使用工具: Googl 浏览器+PostMan 插件 写了个 控制器 添加了个Action,结果呢?GET 方式请求没问题. POST一直,在服务器端获取不了参数...找了官方的文档 .各种雨里雾 ...
- Qt编程之QImage类小结
最近用Qt做图像处理,以下references是需要用到的 references: http://blog.csdn.net/lyc_daniel/article/details/9193881 ht ...
- 机器学习 1、R语言
R语言 R是用于统计分析.绘图的语言和操作环境.R是属于GNU系统的一个自由.免费.源代码开放的软件,它是一个用于统计计算和统计制图的优秀工具. 特点介绍 •主要用于统计分析.绘图.数据挖掘 •R内置 ...