单例模式保证一个类仅有一个实例,并提供一个访问它的全局访问点。当系统中需要某个类只能有一个实例时,就可以采用单例模式。
单例模式具有的特点如下:
- 单例类有且仅有一个实例对象
- 单立类必须自己创建自己的唯一实例
- 单立类必须给所有其他对象都能提供这个实例类
生成单例对象的关键是构造方法的私有化,构造函数使用private关键字进行修饰,避免了外部通过new 关键字进行实例化
2.1 直接实例化public class Singleton1 {
private Singleton1(){
}
//直接产生单例实例,在类加载时完成初始化,整个项目中只出现一次
private static final Singleton1 singleton1=new Singleton1();
public static Singleton1 getInstance(){
return singleton1;
}
}
2.2 延迟实例化
public class Signleton2 {
private Signleton2() {
}
private static Signleton2 signleton2 = null;
public static Signleton2 getInstance() {
//为了避免多线程下判断(signleton2==null)均成立,内部使用synchronized关键字,对类对象Signleton2进行加锁
//双重锁保证了是线程安全的
if (signleton2 == null) {
synchronized (Signleton2.class) {
if (signleton2 == null) {
signleton2 = new Signleton2();
}
}
}
return signleton2;
}
}
2.3 静态内部类相对于直接实例化,延迟实例化的方式确保了仅仅只会在程序确实需要使用到单例对象时才会创建该实例对象。
public class Signleton3 {
private Signleton3 (){
System.out.println("start init");
}
private static class inner{
private static final Signleton3 signleton3=new Signleton3();
}
public static Signleton3 getInstance(){
return inner.signleton3;
}
}
静态内部类测试
public class Main {
public static void main(String[] args) {
//实例化1
Signleton3 instance=Signleton3.getInstance();
//实例化2
Signleton3 instance1=Signleton3.getInstance();
if(instance==instance1){
System.out.println("实例后的对象相等");
}
}
}
运行main方法后输出如下
start init
实例后的对象相等
分析如下:
实例化1时,对象的初始化在调用inner.signleton3时,才会运行静态内部类中的Signleton3 signleton3=new Signleton3();从而产生单例对象。此时输出构造方法中的start init。运行到实例化2时,并没有再次进入到构造方法,仅仅实例化一次
当java虚拟机加载类字节码时,单例对象并不是立即加载的,只有运行到inner.signleton3时对象才会被动态实例化,与延迟实例化实现单例对象的效果一致。从虚拟机效率来说,利用静态内部类生成单例对象是最优的



