单例模式
什么是单例模式Singleton?
Singleton:在JAVA中指单例设计模式,它是软件开发中最常用的设计模式之一。
这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保只有单个对象被创建。这个类提供了一种访问其唯一的对象的方式,可以直接访问,不需要实例化该类的对象。
单:唯一
例:实例
基础知识:
类: 是指描述一种事物的定义,是个抽象的概念
实例:指实际存在的例子,事物的一个具体的个体,或是具体的东西。
比如说:“人”是一个类。“张三”是人类的一个具体例子,就是实例化。
在编程时也是同样的道理,你先自己定义一个“类”,当你需要用时,用“类”的定义来创造一个具体的例子。
用类的定义来创建一个实例,就叫做类的实例化。
单例设计模式,即某一个类在整个系统中只能有一个实例对象可以被获取和使用的代码模式
注意:
1、单例类只能有一个实例。
怎么调用呢?构造器私有化
2、单例类必须自己创建自己的唯一实例。
含有一个改类的静态变量来保存这个唯一的实例
3、单例类必须给所有其他对象提供这一实例。
对外提供获取该实例对象的方式:
(1)直接暴露出来
(2)用静态变量get方法来获取
实例:
1、一个班级只有一个班主任。
2、Windows是多进程多线程的,在操作一个文件的时候,就不可避免地出现多个进程或线程同时操作一个文件的现象,所以所有文件的处理必须通过唯一的实例来进行。
3、一些设备管理器常常设计为单例模式,比如一个电脑有两台打印机,在输出的时候就要处理不能两台打印机打印同一个文件。
优点:
1、在内存里只有一个实例,减少了内存的开销,尤其是频繁的创建和销毁实例(比如管理学院首页页面缓存)。
2、避免对资源的多重占用(比如写文件操作)。
缺点:
没有接口,不能继承,与单一职责原则冲突,一个类应该只关心内部逻辑,而不关心外面怎么样来实例化。
几种常见形式:
饿汉式∶直接创建对象,不存在线程安全问题
-直接实例化饿汉式(简洁直观)
-枚举式(最简洁)
-静态代码块饿汉式(适合复杂实例化)
懒汉式:延迟创建对象
-线程不安全(适用于单线程)
-线程安全(适用于多线程)
-静态内部类形式(适用于多线程)
饿汉式:
package com.tedu.single;
/**
* 饿汉式:
* 直接创建实例对象,不管你是否需要这个对象,都会创建
*
* 1.构造器私有化 private
* 2.自行创建,并且静态变量保存 static
* 3.向外提供这个实例 public
* 4.强调这是一个单例,我们可以final修饰
*
* 常量我们习惯性的写为大写 INSTANCE
*/
public class Singleton1 {
public static final Singleton1 INSTANCE = new Singleton1();
private Singleton1(){
}
}
获取方式测试:
package com.tedu.test;
import com.tedu.single.Singleton1;
public class TestSingleton1 {
public static void main(String[] args) {
Singleton1 s = Singleton1.INSTANCE;
System.out.println(s);
}
}
运行结果:
枚举:
package com.tedu.single;
/**
* 枚举类型:表示该类型的对象是有限的几个
* 我们可以限定为一个,就成了单例
*/
public enum Singleton2 {
INSTANCE;
}
获取方式测试:
package com.tedu.test;
import com.tedu.single.Singleton2;
public class TestSingleton1 {
public static void main(String[] args) {
Singleton2 s = Singleton2.INSTANCE;
System.out.println(s);
}
}
运行结果:
我们可以发现着两种模式好像没什么区别,基本上一样,JDK1.5之前与JDK1.5之后的分别。
静态代码块:
package com.tedu.single;
import com.sun.xml.internal.bind.v2.runtime.unmarshaller.XsiNilLoader;
import java.io.IOException;
import java.util.Properties;
//静态代码块
public class Singleton3 {
public static final Singleton3 INSTANCE;
//什么时候可能会用到这种方法呢?属性需要初始化
private String info;
static {
try {
Properties pro=new Properties();
pro.load(Singleton3.class.getClassLoader().getResourceAsStream("single.properties"));
INSTANCE = new Singleton3(pro.getProperty("info"));
} catch (IOException e) {
e.printStackTrace();
}
}
private Singleton3(String info){
this.info=info;
}
public static Singleton3 getINSTANCE() {
return INSTANCE;
}
public String getInfo() {
return info;
}
public void setInfo(String info) {
this.info = info;
}
}
以上就是饿汉式的三种写法
懒汉式:
package com.tedu.test;
import com.tedu.single.Singleton4;
public class TsetSingleton4 {
public static void main(String[] args) {
Singleton4 s1= Singleton4.getInstance();
Singleton4 s2= Singleton4.getInstance();
System.out.println(s1==s2);
System.out.println(s1);
System.out.println(s2);
}
}
测试:
package com.tedu.test;
import com.tedu.single.Singleton4;
public class TsetSingleton4 {
public static void main(String[] args) {
Singleton4 s1= Singleton4.getInstance();
Singleton4 s2= Singleton4.getInstance();
System.out.println(s1==s2);
System.out.println(s1);
System.out.println(s2);
}
}
运行结果: