设计模式之单例模式
是Java设计模式中最常用的模式之一,是面试过程中经常考察的点,需要手写单例。单是唯一,例是实例,即某个类在系统中只能存在唯一的一个实例对象可供使用。
二、要点
1、 构造器私有化,由于类的实例唯一,所以外界不能通过new关键字创建实例对象
2、 在类的内部创建实例,并定义一个静态成员变量保存类的实例
3、 需要向外界提供获得实例的方式
a) 直接暴露
b) 通过get方法获取
三、几种常见的单例模式,一般分为两类:饿汉式和懒汉式
饿汉式
随着类的加载不管需不需要都会直接创建实例对象,不存在线程安全问题。
a. 直接实例化 (简单直观)
/**
* 单例模式之直接实例方式
* @author lux81
*
*/
public class Singleton1 {
//静态常量保存实例对象
public static final Singleton1 INSTANCE = new Singleton1();
//构造器私有化
private Singleton1() {
System.out.println("直接实例化");
}
}
//调用测试
public class TestSingleton1 {
public static void main(String[] args) {
//直接通过类名.属性 调用
Singleton1 instance = Singleton1.INSTANCE;
System.out.println(instance);
}
}
b. 枚举式 (最简洁)
/**
* 单例模式之枚举方式
* 枚举类型 表示该类型的对象是有限的几个
* 我们可以限定为一个 就成了单例
* @author lux81
*
*/
public enum Singleton2 {
INSTANCE;
//添加一个测试方法
public void sayHello() {
System.out.println("hello");
}
}
//测试类
public class TestSingleton2 {
public static void main(String[] args) {
Singleton2 instance2 = Singleton2.INSTANCE;
//调用测试方法 输出 hello
instance2.sayHello();
//直接输出实例对象名
System.out.println(instance2);
}
}
c. 静态代码块 (适合复杂实例化)
在实例化对象的时候可能会初始化一些数据
/**
* 单例模式之静态代码块方式
* 加入在实例化对象时需要初始化一些配置信息可以使用该方式
* @author lux81
*
*/
public class Singleton3 {
public static final Singleton3 INSTANCE;
//测试从配置文件中获取初始化数据
private String info;
static {
//加载配置文件
Properties prop = new Properties();
try {
prop.load(Singleton3.class.getClassLoader().getResourceAsStream("test.properties"));
} catch (IOException e) {
throw new RuntimeException(e);
}
//实例化对象 并获取初始化数据
INSTANCE = new Singleton3(prop.getProperty("name"));
}
private Singleton3(String info) {
this.info = info;
}
//setter和 getter方法略
}
//测试
public class TestSingleton3 {
public static void main(String[] args) {
Singleton3 instance3 = Singleton3.INSTANCE;
//调用方法获取配置文件 name属性值
System.out.println(instance3.getInfo());
}
}
懒汉式
延迟创建或者是需要的时候才创建
a. 线程不安全(适用于单线程)
/**
* 单例模式之懒汉式(线程不安全,适合单线程)
* @author lux81
*
*/
public class Singleton4 {
private static Singleton4 instance;
private Singleton4() {
}
//提供给外面获取实例对象的get方法
public static Singleton4 getInstance() {
//如果对象不存在则创建,已经存在直接返回
if (instance == null) {
//此处如果在多线程的情况下,会出现创建多个不同对象的情况
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
instance = new Singleton4();
}
return instance;
}
}
//测试
public class TestSingleton4 {
public static void main(String[] args) {
Singleton4 s1 = Singleton4.getInstance();
Singleton4 s2 = Singleton4.getInstance();
System.out.println(s1 == s2); //返回结果 true
//使用多线程方式测试
Callable<Singleton4> c = new Callable<Singleton4>() {