3、用私有构造器或者枚举类型强化Singleton属性
singleton指仅仅被实例化一次的类
1.公有静态成员是final域:
public class A{
public static final A INSTANCE=new A();
private A(){}
}
2.静态工厂方法:
public class A{
public static final A INSTANCE=new A();
private A(){}
public static A getInstance(){ return INSTANCE };
}
3.包含单个元素的枚举类型
public enum A{
INSTANCE;
}
这种方法在功能上与公有域方法相近,但是他更加简洁,无偿的提供了序列化机制,绝对防止多次实例化,即使是在面对复杂的序列化或者反射攻击的时候。
4、通过私有构造器强化不可实例化的能力
企图通过将类做成抽象类来强制该类不可被实例化是行不通的,该类可以被子类化,并且该子类可以被实例化。这样做容易误导用户,以为这种类是专门为了继承而设计的。
简单的确保类不会被实例化的方法:
由于只有当类不包含显式的构造器的时候,编译器才会生成缺省的构造器,因此我们只需要让这个类包含私有构造器。
5、避免创建不必要的对象
以下方法isBabyBoomer检查person是否在1946-1965间出生
public class Person{
//未初始化
private final Date birthDate;
public boolean isBabyBoomer(){
Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
Date boomStart=gmtCal.getTime();
gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
Date boomEnd=gmtCal.getTime();
return birthDate.compareTo(boomStart)>=0&&birthDate.compareTo(boomEnd)<0;
}
}
每次调用都会新建一个Calendar,一个timezone,两个Date实例。以下使用
静态的初始化器:
public class Person{
//未初始化
private final Date birthDate;
static {
Calendar gmtCal=Calendar.getInstance(TimeZone.getTimeZone("GMT"));
gmtCal.set(1946,Calendar.JANUARY,1,0,0,0);
Date boomStart=gmtCal.getTime();
gmtCal.set(1965,Calendar.JANUARY,1,0,0,0);
Date boomEnd=gmtCal.getTime();
}
public boolean isBabyBoomer(){
return birthDate.compareTo(boomStart)>=0&&birthDate.compareTo(boomEnd)<0;
}
}
改进后只在初始化的时候才创建实例,而不是在每次调用isBabyBoomer的时候都创建的实例。
如果改进后的person类被初始化了,它的的isBabyBoomer方法却永远不会被调用,那就没有必要初始化boomStart了,通过延迟初始化(lazily Initializing)即把对这些域的初始化延迟到第一次被调用的时候进行,则有可能消除这些不必要的初始化工作,但是不建议这么做。这样做会使方法的实现更加复杂,从而无法将性能显著提高到超过已经达到的水平。
6、消除过期的对象引用
“内存泄漏“的例子
public class Stack{
private Object[] elements;
private int size=0;
private static final int DEFAULT_INITIAL_CAPACITY=16;
public Stack(){
elements=new Object[DEFAULT_INITIAL_CAPACITY];
}
public void push(Object e){
ensureCapacity();
elements[size++]=e;
}
public Object pop(){
if(size==0)
throw new EmptyStackException();
return elements[--size];
}
private void ensureCapacity(){
if(elements.length==size)
elements=Arrays.copyOf(elements, 2*size+1);
}
}
栈中弹出来的对象将不会被当做垃圾回收,即使使用栈的程序不再引用这些对象,它们也不会被回收。这是因为栈内部维护着对这些对象的过期引用(obsolete reference)。
改进:
<pre name="code" class="java">public Object pop(){
<span style="white-space:pre"> </span>if(size==0)
throw new EmptyStackException();
Object result =elements[--size];
elements[size]=null;
return result;
}
清空过期引用的另一个好处,如果它们以后
又被错误的解除引用,程序会立即抛出NullPointerException异常,而不是悄悄地运行下去。尽快地检测程序中的错误总是有好处的。