Singleton指仅仅被实例化一次的类。Singleton通常被用来代表那些本质上唯一的系统组件。
实现单例模式常见有三种方式:
静态成员
package Singleton强化;
public class Elvis {
public static final Elvis INSTANCE=new Elvis();
private Elvis() {
}
public void leaveTheBuilding(){
System.out.println("Hello!...");
}
public static void main(String[] args) {
Elvis elvis=new Elvis();
elvis.leaveTheBuilding();
}
}
静态工厂方法
package Singleton强化;
public class Elvis1 {
private static final Elvis1 INSTANCE =new Elvis1();
private Elvis1(){};
public static Elvis1 getInstance(){return INSTANCE;};
public void leaveTheBuilding(){
System.out.println("Hello!...");
}
public static void main(String[] args) {
Elvis1 elvis1=Elvis1.getInstance();
elvis1.leaveTheBuilding();
}
}
但是这两种方式不能完全保证全局唯一对象。享有特权的客户端可以借助反射机制设置AccessibleObject.setAccessible(ture),改变构造器访问属性,调用私有构造器。让它在被要求创建第二个实例的时候抛出异常。
package Singleton强化;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* 第二次创建实例的时候抛出异常。
*/
public class Elvis1 {
private static int count=0; //记录创建次数
private static final Elvis1 INSTANCE =new Elvis1();
private Elvis1(){
if (count>0){
throw new IllegalArgumentException("Cannot create Elvis1 twice");
}
count++;
}
public static Elvis1 getInstance(){return INSTANCE;};
public void leaveTheBuilding(){
System.out.println("Hello!...");
}
public static void main(String[] args) throws IllegalAccessException, InvocationTargetException, InstantiationException {
Elvis1 elvis1=Elvis1.getInstance();
// elvis1.leaveTheBuilding();
//手动反射去创建实例化对象
Constructor<?> constructor = Elvis1.class.getDeclaredConstructors()[0];
constructor.setAccessible(Boolean.TRUE);
Elvis1 elvis11 = (Elvis1) constructor.newInstance();
elvis11.leaveTheBuilding();
}
}
抛出不能创建两次的异常:
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
at Singleton强化.Elvis1.main(Elvis1.java:30)
Caused by: java.lang.IllegalArgumentException: Cannot create Elvis1 twice
at Singleton强化.Elvis1.<init>(Elvis1.java:14)
... 5 more
如果上面两种实现的Singleton是可序列化的,加上implements Serializable只保证它是可序列化的,为了保证反序列化的时候,实例还是Singleton的,必须声明实例域都是瞬时(transient)的,并提供readResolve方法。否则,每次反序列化一个序列化实例,都会创建一个新的实例。下面的例子每次反序列化都会生成新的实例对象:
package Singleton强化;
import java.io.*;
public class Elvis implements Serializable{
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void leaveTheBuilding() {
System.out.println("Hell!...");
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Elvis elvis = new Elvis();
//elvis.leaveTheBuilding();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/1.6/elvis.txt "));
oos.writeObject(elvis);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/1.6/elvis.txt "));
Elvis o = (Elvis) ois.readObject();
ois.close();
System.out.println(elvis == o); //false
}
}
加入readResolve方法之后:
package Singleton强化;
import java.io.*;
public class Elvis implements Serializable {
public static final Elvis INSTANCE = new Elvis();
private Elvis() {
}
public void leaveTheBuilding() {
System.out.println("Hell!...");
}
private Object readResolve() {
// Return the one true Elvis and let the garbage collector}
// take care of the Elvis impersonator.}
return INSTANCE;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
//E:/1.6/elvis.txt
Elvis elvis = Elvis.INSTANCE;
elvis.leaveTheBuilding();
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("E:/1.6/elvis.txt "));
oos.writeObject(elvis);
oos.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("E:/1.6/elvis.txt "));
Elvis o = (Elvis) ois.readObject();
ois.close();
System.out.println(elvis == o); //ture
}
}
单元素枚举类型
单元素枚举:只需要编写一个包含单元素的枚举类型
package Singleton强化;
public enum Elvis2 {
INSTANCE;
public void leaveTheBuilding(){
System.out.println("Hello!...");
}
public static void main(String[] args) {
Elvis2 elvis2=Elvis2.INSTANCE;
elvis2.leaveTheBuilding();
}
}
通过枚举实现Singleton更加简洁,同时枚举类型无偿提供了序列化机制,可以防止序列化的时候多次实例化同一对象。枚举类型也可以防止反射攻击,当你试图反射实例化枚举实例的时候会抛出IllegalArgumentException异常。
总结
单元素的枚举类型已经成为实现Singleton的最佳方法。