第1条:考虑用静态工厂方法代替构造器
1.what is?
此处的静态工厂方法与设计模式中的工厂模式不一样。
比如类
class Person{
//A的构造器
public A(){};
//A的静态工厂方法可以是
static Person Male; //男人集合
static Person Female; //女人集合
public static getMale(){
return Person.Male;
}
}
2.why?
》第一个优势:它们有直接的名称。而重载的构造器没有名称,没有说明的情况下可能很难辨认。
》第二个优势:不必每次都创建新对象。通过构造器每次都new出一个对象,而像上例的getMale则可以重用一个对象。
》第三个优势:可以返回任何子类的对象,同时又不会让对象的类变成公有的,更加灵活,api更加简洁。同时在编写该静态工厂方法时,子类可以不必存在。
e.g.:服务提供者框架。其中有三个重要的组件:服务接口,服务提供者注册API(注册后客户端可访问该服务),服务访问API(客户端获取服务实例)。第四个可选组件是服务提供者接口(用于创建其服务实现的实例),如果没有,就按照类名注册,并通过反射方式实例化。
》第四个优势:创建参数化类型实例的时候,它们使代码变得更加简洁。
e.g.:Map<String,List<String>> m = new HashMap<String,List<String>>();
可以使用静态工厂方法进行类型推导
public static <K,V> HashMap<K,V> newInstance(){ return new HashMap<K,V> ();}
貌似jdk1.7里面就是这么干的。
3.but
》第一个缺陷:类如果不含public或者protected的构造器,就不能被子类化
》第二个缺陷:与其他静态方法没有区别,不好辨认。
第2条:遇到多个构造器参数时要考虑用构建器
1.what?
当构造器有n个参数时程序员习惯用重叠构造器
class A{
public A(){this.A(null)}
public A(B){
this.A(B,null)
}
public A(B,C){
this.A(B,C,null)
}
public A(B,C,D)
….
}
很淡疼对不对?
替代品有JavaBeans:
class A{
B,C,D;
public A(){}
//getter and setter
}
但是这样分成多个步骤创建实例,会产生多线程下不安全的问题,必须保证线程安全的情况下再这么做。
于是第三种替代品出现,Builder模式
class A{
B,C,D;
static class Builder{
B,C,D;
public Builder(){}
public Builder setB(B){
this.B = B;
return this;
}
public Builder setC(C){
this.C = C;
return this;
}
public Builder setD(D){
this.D = D;
return this;
}
public A build(){
return new A(this);
}
}
private A(Builder b){
this.B = b.B;
this.C = b.C;
this.D = b.D;
}
}
相信都见过,这种叫做构建器。在build或者setter方法中对参数做强约束检查。
缺陷:需要先new构建器,参数设置也冗长,如果参数较少(3个以内)可以不用。
总之,如果类的构造器或者静态工厂中具有多个参数时,Builder模式是种不错的选择。
第3条:用私有构造器或者枚举类型强化Singleton属性,即单例
单例大家都很熟悉,用的多。比如
class A{
private final static A INSTANCE = new A();
private A(){}
public void getInstance(){
return INSTANCE;
}
}
但是通过反射机制依然是可以访问私有属性的。而且如果A需要序列化,加上implements Serrializable是不够的,为了保证单例,必须声明所有实例域都是transient的,并提供readResolve方法,否则每次反序列化都会创建一个新实例。
private Object readResolve(){
return INSTANCE;
}
从jdk1.5开始,实现单例还有第三种方法,利用包含单个元素的枚举类型:
public enum A{
INSTANCE;
}
第4条:通过私有构造器强化不可实例化的能力
第5条:避免创建不必要的对象。避免无意识的自动装箱。小对象的创建销毁很廉价,不要用对象池维护,消耗大的比如数据库会采用连接池。
第6条:消除过期的对象引用
》情况一:Stack类自己管理内存,对于pop出的数据自己认为是过期的,但是对于垃圾回收器来说并不清楚,所以pop的时候主动释放才能避免内存泄漏。类似这种情况,只要类是自己管理内存,就应该警惕内存泄漏问题。
》情况二:缓存中的对象引用
》情况三:监听器和其他回调。
(ps:以上情况我在安卓开发中亲身经历过无数遍)
第7条:避免使用终结方法finalize
1)终结方法不一定及时执行,且有性能损失。
2)替代方案是显式定义一个的终止方法,并要求该类的每个实例不再有用时调用该方法。如果该类已经被终止,再次调用应该抛出IllegalStateException
(ps:这个也是,安卓开发中有时候activity无法释放,需要自己手动控制释放)
最优设计:
try{}catch(){}finally{ 自定义的终止方法 },java的io流都有自己的终止方法。
3)
》终结方法的好处一:当你忘了调用自己的终止方法时,终结方法可以充当安全网,迟到总比不到好。如果到了这一步应该加个错误日志,这是一个bug
》终结方法的第二个合理用途:当java对象通过native方法委托给一个本地对象时,称为本地对等体,很明显java的垃圾回收器是不知道它的,java对象被回收时这个本地对象还在蹦哒。当它不具有关键资源的情况下,终结方法就是最合适的。如果具有关键资源,就需要显示的终止方法。
4)终结方法链不会自动执行,应该在try块中终结子类,然后finally块中调用超类的终结方法。
5)总之,除非作为安全网,或者是终止非关键的资源,否则不要使用终结方法。