单例设计模式
- (1)什么是单例设计模式
单:唯一
即某个类在整个系统中只能有一个实例对象
可被获取和使用的代码模式。
在Java中即指单例设计模式,它是软件开发中最常用的设计模式之一。 - (2)实例
例如:代表JVM运行环境的Runtime类
public class Runtime {
private static Runtime currentRuntime = new Runtime();
/**
* Returns the runtime object associated with the current Java application.
* Most of the methods of class <code>Runtime</code> are instance
* methods and must be invoked with respect to the current runtime object.
*
* @return the <code>Runtime</code> object associated with the current
* Java application.
*/
public static Runtime getRuntime() {
return currentRuntime;
}
/** Don't let anyone else instantiate this class */
private Runtime() {}
单例设计模式
- (1)单例的要点
》》某个类只能有一个实例 private static
》》它必须自行创建这个实例 private 构造方法
》》它必须自行向整个系统提供这个实例; getXxx() - (2)为什么?
构造器私有化
含有一个该类的静态变量来保存这个唯一的实例
对外提供获取该实例对象的方式:
(1)直接暴露(2)用静态变量的get方法获取
//1:静态的私有的成员变量
//2:私有的构造方法
//3:公有的静态的获取方法
class MyClass {
private static MyClass obj = new MyClass();
private MyClass() {
}
public static MyClass getInstance() {
return obj;
}
}
public class Test03单例 {
@Test
public void test01() {
/* MyClass obj1 = MyClass.getInstance();
MyClass obj2 = MyClass.getInstance();
System.out.println(obj1);
System.out.println(obj2);
System.out.println(obj1==obj2);*/
//如果构造方法不是私有的,可以创建多个对象
//定义:项目中,该类只能有一个对象
/*MyClass obj3 = new MyClass();
MyClass obj4 = new MyClass();
System.out.println(obj3);
System.out.println(obj4);*/
//如果没有公有的静态的获取方法,无法使用使用该单例
//System.out.println(MyClass.obj);
//如果静态的成员变量改成公有的,有可能被置成null
//MyClass.obj = null;
}
}
几种常见形式
共两类
》在使用获取方法时,是否已经初始化了实例对象
》饿汉式:已有实例对象 ,再调用
》懒汉式:调用才创建实例对象
(1)饿汉式
直接创建对象,不存在线程安全问题(加载即创建)
直接实例化饿汉式(简洁直观)
静态变量赋值
//第一种 private static MyClass obj = new MyClass();
class MyClass {
private static MyClass obj = new MyClass();
private MyClass() {
System.out.println("MyClass构造方法执行了");
}
public static MyClass getInstance() {
System.out.println("getInstance方法执行了");
return obj;
}
}
public class Test03单例 {
@Test
public void test01() {
MyClass obj1 = MyClass.getInstance();
MyClass obj2 = MyClass.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
}
枚举式(最简洁)
//第二种 使用枚举 enum,枚举内只能写一个对象名
enum MyClass {
obj1
}
public class Test03单例 {
@Test
public void test01() {
// MyClass obj1 = new MyClass();
MyClass obj1 = MyClass.obj1;
MyClass obj2 = MyClass.obj1;
System.out.println(obj1);
System.out.println(obj2);
}
}
静态代码块饿汉式(适合复杂实例化)****
静态代码块
//第三种 可以静态代码块中初始化对象
class MyClass {
private static MyClass obj = null;
static {
//可以读配置文件 读properties文件,获取数据库的四大信息
obj = new MyClass();
}
private MyClass() {
System.out.println("MyClass构造方法执行了");
}
public static MyClass getInstance() {
System.out.println("getInstance方法执行了");
return obj;
}
}
public class Test03单例 {
@Test
public void test01() {
MyClass obj1 = MyClass.getInstance();
MyClass obj2 = MyClass.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
}
(2)懒汉式
lazy 延迟创建对象(在调用时才创建)
线程不安全(适用于单线程)
线程不安全
class MyClass {
private static MyClass obj = null;
private MyClass() {
System.out.println("MyClass构造方法执行了");
}
public static MyClass getInstance() {
System.out.println("getInstance方法执行了");
if (obj == null) {
//创建对象
obj = new MyClass();
}
return obj;
}
}
public class Test03单例懒汉 {
@Test
public void test01() {
MyClass obj1 = MyClass.getInstance();
MyClass obj2 = MyClass.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
}
线程安全
线程安全(适用于多线程)加同步关键字+if优化判断
//懒汉:调用get时,才在get内部初始化(催作业)
class MyClass {
private static MyClass obj = null;
private MyClass() {
System.out.println("MyClass构造方法执行了");
}
public static MyClass getInstance() {
System.out.println("getInstance方法执行了");
//类在内存中只有一份,所以可以拿当锁
//有了唯一的一把锁之后,所有的线程就必须排队
if (obj == null) {//2:因为synchronized会让线程排队,降低效率。在进入加锁代码之,满足条件的直接return
synchronized (MyClass.class) {
if (obj == null) {//1:判断是否有对象 ,没有才创建
//创建对象
obj = new MyClass();
}
}
}
return obj;
}
}
public class Test03单例懒汉 {
@Test
public void test01() {
MyClass obj1 = MyClass.getInstance();
MyClass obj2 = MyClass.getInstance();
System.out.println(obj1);
System.out.println(obj2);
}
}
静态内部类形式
(适用于多线程)静态内部类的静态变量
class OutMyClass {//外部类
public class InnerClass {//内部类
}
public static class MyClass {//静态内部类
//静态变量
private static MyClass obj = new MyClass();
}
public static MyClass getIntance() {
return MyClass.obj;
}
}
public class Test03单例懒汉 {
@Test
public void test01() {
OutMyClass.MyClass obj1 = OutMyClass.getIntance();
OutMyClass.MyClass obj2 = OutMyClass.getIntance();
System.out.println(obj1);
System.out.println(obj2);
}
}
内部类:在A类中,定义B类,B则是A的内部类
静态内部类:就在B类上加static