该知识点是自己从书籍中学习的笔记。
单例:
是指类只能够被实例化一次。
单例通常是表示一个惟一的系统组件,如widows管理者或者文件系统。将一个类制作成单例对于测试用户会变的困难,因为替换掉一个单例的模拟实现类是不太可能的,除非该单例实现了一个作为它自己类型的接口。
实现方法:
在jdk1.5之前,有两种方式来实现单例,这两种方法都是基于构造方法是私有的和导出一个获取单一实例的公有静态成员的方式来实现的。
方法1:
public class Singleton1 {
public static final Singleton1 singleton =new Singleton1();
private Singleton1() {
if(Singleton1.singleton != null){
try {
throw new Exception();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Singleton1 s = Singleton1.singleton;
Singleton1 s1 = Singleton1.singleton;
System.out.println(s == s1);
}
}
使用这种方式时,私有的构造方法仅仅能使用一次,并且是用来初始化singleton实例的。由于没有public或protected的构造方法,所以就保证了Singleton1的惟一性,当Singleton1被初始化的时候,singleton实例也会被实例化,并且singleton只有一个。任何用户都不能够改变,除非该用户使用反射机制。要避免用户使用反射机制来创建实例的话,可以修改构造方法来判断。所以上面的代码打印结果是true。
方法2:
public class Singleton2 {
private static final Singleton2 singleton =new Singleton2();
private Singleton2() {
}
public static Singleton2 getInstance(){
if(singleton == null){
try {
throw new Exception();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return singleton;
}
public static void main(String[] args) {
Singleton2 s = Singleton2.getInstance();
Singleton2 s1 = Singleton2.getInstance();
System.out.println(s == s1);
}
}
方法3:
Jdk1.5版本以来,可以使用枚举类型来创建单例。如下:
public enum SingletonEnum {
SINGLETON;
public static void main(String[] args) {
SingletonEnum s = SingletonEnum.SINGLETON;
SingletonEnum s1 = SingletonEnum.SINGLETON;
System.out.println(s == s1);
}
}
优点:
方法1优点:
很清楚的表明该类是单例,在性能上较优先。
方法2优点:
1).可以修改public static Singleton2 getInstance()方法来决定是否将该类设置为单例。注意:在使用线程的时候,就会产生不同的实例,因为一个线程就会有一个实例。
2).可以使用泛型。
方法3优点:
1).该方法功能等同于方法1,但它更简洁,提供免费的序列化机制,并提供一个
铁定针对多个实例的保证,即使是在面对复杂序列化或反射攻击。
2).虽然这种方法尚未得到广泛通过一个单元素的枚举类型是最好的方式来实现一个单例。
备注
无论方法1还是方法2,如果将单例做成序列化的话,在反序列化的时候,单例会不起作用,会创建无数个实例,这是不应该的。在单例类序列化的时候,不仅是实现Serializable接口,同时其fields必须声明为transient,并且提供一个readResolve 方法,如下:
// readResolve method to preserve singleton property
private Object readResolve() {
// Return the one true Singleton2 and let the garbage collector
// take care of the Elvis Singleton2.
return singleton;
}