Effective Java理解笔记系列-第1条-何时考虑用静态工厂方法替代构造器?
为什么写这系列博客?
在阅读《Effective Java》这本书时,我发现有许多地方需要仔细认真地慢慢阅读并且在必要时查阅相关资料才能彻底搞懂,相信有些读者在阅读此书时也有类似感受;同时,在解决疑惑的过程中,还存在着有些内容不容易查找、查找到的解答质量不高等问题,于是我决定把我阅读此书收获到的东西写成博客,期望能够解答某些读者之困惑。
为了方便大家阅读时按章节查找,我会按照原书籍写作顺序来划分博客章节。博客中主要包含以下内容:
- 我对原文内容的理解(再加工)
- 一些补充知识(需要理解这些知识才能真正理解该章节内容)
创建和销毁对象
何时考虑用静态工厂方法替代构造器?
无法准确描述
该实例无法通过构造器名称和参数完整描述。--》目的:方便用户正确调用。
BigInteger(int,int,Random) // 使用构造器
BigInteger.probablePrime(int,int,Random)//静态工厂方法
//以上构造器返回的实例可能为质数,通过构造器名称BigInteger和参数列表无法体现出质数,所以用静态工厂方法更好。
重复利用缓存
不可变类在创建实例时重复利用事先构建好或已缓存的实例。--》目的:避免创造不必要对象,降低内存提升性能;客户端可以用==操作符替代equals方法,提升性能,如:
public static final Boolean TRUE = new Boolean(true);
public static final Boolean FALSE = new Boolean(false);
public static Boolean valueOf(boolean b){
return b? Boolean.TRUE:Boolean.FALSE;//通过valueOf调用得到的某个值的实例都是一个实例,所以可以用==来比较
}
隐藏实现类
返回接口类型,隐藏实现类--》目的:客户端使用只需关注接口功能即可,而不需要关注具体实现类;可灵活替换返回对象,而客户端不需要修改代码。
-
隐藏实现类的方法:使用内部类
- 静态内部类:Collections类中的UnmodifiableList内部类
- 实例内部类:LinkedList类中的ListItr内部类
-
导出实现类的方法:
- 静态工厂导出,如:Collections类中的静态工厂方法:unmodifiableList
- 通过实例方法导出,如:LinkedList类中的实例方法:listIterator
-
其他补充知识:
-
当内存中只需要一份,没有多个实例化的需求,不需要多份时,就考虑使用静态变量和静态方法(注意保持不可实例化,私有构造函数并抛出异常),如:各种工具类(java.lang.Math);管理器类(JDBC的java.sql.DriverManager)
-
内部类:
-
使用场景:该内部类只和当前外部类(相对而言)相关,而和其他类无关,其他类不需要知晓该类的存在。
-
静态or实例?如果该内部类不需要使用实例域或者外部类没有实例域,用静态内部类;反之用实例内部类
-
方法内部类和匿名内部类如何选择?
- 这两个类都是只限定在当前方法内可用,方法外不可用
- 如果只需要创建一个对象,使用匿名内部类即可;反之,需要多次创建对象,那么使用方法内部类
-
匿名内部类的常见使用场景:定义比较器或者事件响应逻辑
-
框架开发经验:考虑哪部分是不变的固定逻辑,哪部分是开发者需要自定义的逻辑,提供一个接口让开发者实现即可。
-
-
避免繁杂类型参数
利用编译器的类型推导,避免实例化时编写繁杂的类型参数--》目的:让代码更加简洁。
//未使用静态工厂写法
Map<String,List<String>> map = new HashMap<String,List<String>>();
//工具类
public class MapUtil{
//避免实例化
private MapUtil{}
//静态工厂方法
public static <K,V> HashMap<K,V> newInstance(){
return new HashMap<K,V>();
}
}
//使用静态工厂写法
Map<String,List<String>> map = MapUtil.newIntance();
总结
提升简洁性:第四条
提高易用性:第一条;第三条前半部分
可扩展性:第三条后半部分
提升性能:第二条