核心作用:保证一个类只有一个实例,并且提供一个访问该实例的全局访问点。
优点:当生成一个对象的需要比较多的资源时,只生成一个实例减少了系统性能开销,如读取配置时。
单例模式可以设置系统全局访问点,优化共享资源访问。
实现的五种方式
一主要︰
-饿汉式(线程安全,调用效率高。但是,不能延时加载。)
-懒汉式(线程安全,调用效率不高。但是,可以延时加载。)
一其他(补充,面试加分)︰
-静态内部类式(线程安全,调用效率高。同时,可以延时加载)
-枚举单例(线程安全,调用效率高,不能延时加载)
-双重检测锁式(由于指令重排所以不安全)·
饿汉式实现
实现方式:
在类的工厂中设置一个类自身的静态引用并立刻创建实例,构造器私有化,公开一个静态方法获取实例。
线程安全来自于加载类时立刻创建对象,类加载是天然线程安全的,不需要加同步块所以方法调用效率高
public class Singleton {
private Singleton(){}
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
懒汉式实现
与饿汉式的区别,加载类是并不直接初始化对象,真正调用该方法的时候才生成对象,有同步块所以调用效率低。
public class Singleton2 {//懒汉式
private static Singleton2 instance=null;
private Singleton2(){}
//方法同步,调用效率低
public synchronized static Singleton2 getInstance(){//延迟加载
if(instance==null){
instance=new Singleton2();
}
return instance;
}
}
双重检测锁式实现
双重检测锁式是懒汉式的一种,方法同步的代价太高,将synchronized关键字放入到方法中,判断无对象时才加锁并创建对象。
public class Singleton {
private static volatile Singleton instance=null;//注意volatile防止指令重排!!!
private Singleton(){//私有构造方法
}
public static Singleton getInstance(){
if(instance==null){
synchronized (Singleton.class){//同步
if(instance==null){
instance=new Singleton();//创建对象
}
}
}
return instance;
}
}
静态内部类实现
静态内部类实现(一种懒汉加载方式)
同时具备线程安全、懒加载、调用效率高
//加载外部类的时候不会立刻加载它的静态内部类,由此实现懒加载
public class Singleton {
//加载外部类的时候不会立刻加载它的静态内部类,由此实现懒加载
//第一次使用静态内部类中的静态成员时才会加载并静态内部类,且初始化其中的静态成员,所以天然线程安全
private static class SingletonClassInstance{
private static final Singleton instance=new Singleton();
}
private Singleton() {
}
//方法不同步,调用效率高
public static Singleton getInstance(){
return SingletonClassInstance.instance;
}
}
反射与反序列化漏洞
反射破解单例模式:通过反射可以跳过权限检测使用私有构造器构造实例。
防止反射破解单例:在私有构造器中,如下:
private Singleton() {//私有构造器
if(instance!=null){ //防止反射破解,若存在实例后再次调用构造器则抛出异常
throw new RuntimeException();
//return;
}
}
反序列化破解单例模式:反序列化时不需要调用私有构造器,直接通过对象流反序列化出新实例。
防止反序列化破解单例:添加一个readResolve() 方法,直接返回已经存在的实例对象
//设置反序列化时直接调用该方法将存在的对象返回
private Object readResolve() throws ObjectStreamException{
return instance;
}
原型模式
通过clone()方法创建新对象,若new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式。New与clone()不同,new为一行行创建新对象,赋值为默认值,clone()是将旧对象从内存中复制一份。
浅克隆
浅克隆指将被克隆对象的所有值复制给新对象,包括被克隆对象成员类的引用,即新对象与旧对象中的成员类引用指向同一个对象。
实现方式:实现Cloneable接口,实例调用clone方法进行浅克隆。
深克隆
在浅克隆的基础上,新对象与被克隆对象的成员类引用不同,深克隆会将成员类对象也克隆出来赋给新对象的成员类引用。
实现方式1(继承Cloneable接口):在浅克隆的基础上,深克隆会重写clone()方法把属性也使用clone()方法复制一份,要修成员类也实现Cloneable接口。
实现方式2(序列化):将被克隆对象进行序列化,再反序列化则可得到深克隆对象,求成员属性与成员类不被transient关键字修饰。