程序在运行时候,通常会生成很多实例。但是我们想在程序中某个东西只存在一个时,就会有“只创建1个实例的需求”。像这样确保只生成一个实例的模式被称之为Singleton模式。即单例设计模式。这个模式必须保证2点。
1、确保任何情况下都绝对只有1个实例。
2、想在程序中表现出“只存在一个实例”。
接下来我们创建一个名字为Singleton的类。
package DesignPattern;
public class Singleton {
private static Singleton singleton = new Singleton();
private Singleton(){
//在这里要将singleton的构造函数设置为private,这是为了,如果从这个类的外部我们调用这个类的构造函数(new Singleton())
//的话就会报错,错误如下:Error:(6, 26) java: Singleton() 在 DesignPattern.Singleton 中是 private 访问控制
//是给程序员不小心在此模式中用了new 类名()来创建实例的一个提醒,当然程序员可以用getInstance方法来获取实例
//为了保证任何情况下都只能生成一个实例,我们将此构造方法设置为private。
System.out.println("只生成了我这一个实例 实例1号");
}
public static Singleton getInstance(){
return singleton;
}
}
(new Singleton())
//的话就会报错,错误如下:Error:(6, 26) java: Singleton() 在 DesignPattern.Singleton 中是 private 访问控制
//是给程序员不小心在此模式中用了new 类名()来创建实例的一个提醒,当然程序员可以用getInstance方法来获取实例
//为了保证任何情况下都只能生成一个实例,我们将此构造方法设置为private。
System.out.println("只生成了我这一个实例 实例1号");
}
public static Singleton getInstance(){
return singleton;
}
}
接下来我们创建一个Main类,来测试。代码如下:
class Main{
public static void main(String[] args) {
System.out.println("程序开始运行");
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
//调用getInstance来获取2个Singleton的实例
//通过判断obj1和obj2是否相等来确认是否为同1个实例
if (obj1==obj2){
System.out.println("obj1和obj2是同一个实例");
}else {
System.out.println("obj1和obj2是不同的实例");
}
System.out.println("程序运行结束");
}
}
代码运行的结果如下:
程序开始运行
只生成了我这一个实例 实例1号
obj1和obj2是同一个实例
程序运行结束
------------------------------------
我们发现,obj1和obj2其实是1个实例,这个实例就是在我们第一次调用getInstance方法时,Singleton类被初始化时,
private static Singleton singleton = new Singleton(); //调用了私有的构造方法,打印 实例1号
static字段singleton被初始化,生成了一个唯一的实例!
单例设计模式使用注意2点:1、我们要定义获取实例的方法时,要设置为static,让它在类初始化时候,就只生成这1个实例
2、为了防止不小心使用new 类名()方法创建实例,我们将构造函数设置成为了private。
我们在这里使用的是“饿汉式”,还有一种是“懒汉式”。
其实它们的总体模式都是一样的,“饿汉式”就是在第一张图片的第3行代码中,我们在创建这个类的具体实例的引用时候,就已经让它new了,指向了具体的对象,即图中的, private static Singleton singleton = new Singleton();。
“懒汉式”的意思就是在第一个图中的第三行,我们这么写,private static Singleton singleton = null
;不让它实例化,而是在调用获取它实例方法时候才,创建对象。再返回。 即在getInstance()方法里这么写:
public static Singleton getInstance(){
if(null==singleton){
singleton = new Singleton(); // 没创建实例,引用为空时候,我们就创建,返回
}
return singleton ;
}
它们的区别就是创建对象的时机不同!
补充:
静态内部类的单例设计模式写法:
/**
* 单例模式 静态内部类版本
* 因为在内部类加载和初始化时候,对象才被创建的。所以线程是安全的
* 静态内部类是不会随着外部类的加载而初始化的,它需要单独初始化
*/
public class SingleTon {
private SingleTon() {
}
private static class Inner{
private static final SingleTon INSTANCE = new SingleTon();
}
public static SingleTon getInstance(){
return Inner.INSTANCE;
}
}
带同步代码块的线程安全的写法:
/**
* *
* 带同步代码块的 线程安全的版本、
*/
public class SingleTonThread {
private SingleTonThread() {
}
private static SingleTonThread instance;
public static SingleTonThread getInstance(){
if (instance==null){
synchronized (SingleTonThread.class){
if (instance ==null){
try {
Thread.sleep(1000);
}catch (Exception e){
e.printStackTrace();
}
instance = new SingleTonThread();
}
}
}
return instance;
}
}