单例设计模式涉及到线程安全等问题,对于初学者来说,掌握基本写法,和代码修饰符的作用即可。
“先有模仿,才能创造”
单例设计模式的作用
该模式用于控制类的实例化过程,不同的情境用不同的设计模式。
单例设计模式特点
1.单例类只能有一个实例
2.单例类必须并且只能自己创建自己的唯一实例对象
3.单例类必须给所有其他对象提供这一实例
就比如:
任务管理器只能打开一个(单例类只能有一个实例),再打开任务管理器还是和之前一样的任务管理器任务管理器不会随意的发生更改(单例类必须并且只能自己创建自己的唯一的实例对象),而且不管在哪个窗口或应用下都能够打开任务管理器(单例类必须给所有其他对象提供这一实例)
饿汉单例模式
饿汉模式在类创建的同时就已经创建好一个静态的对象供系统使用,以后不再改变
在初始化的时候,对象同步创建好了,在堆内存中创建对象开辟了空间,这就使得不管是否调用方法,都提前创建了一个对象。程序执行时就不需要再花时间去创建对象了,该模式占用内存多但反应速度更快。(以空间换取时间)以下为饿汉单例模式常见代码:
package Demo02;
public class Hungry {//饿汉单例模式
//成员变量
private static final Hungry hungry = new Hungry();
//构造器
private Hungry() {}
//成员方法
public static Hungry getHungry(){
return hungry;
}
}
是不是有一种似懂非懂的感觉?不要怕,下面跟着我,将代码抽丝剥茧,走你~~
首先是private static final Hungry hungry = new Hungry();其中的private的作用是什么呢?我们来看代码如果没有这个private会发生什么事情。创建测试类Test
package Demo02;
public class Hungry {//饿汉单例模式
//没private修饰的情况
/*private*/ static final Hungry hungry = new Hungry();
private Hungry() {}
public static Hungry getHungry(){
return hungry;
}
}
package Demo02;
public class Test {
public static void main(String[] args) {
//发现外部可以直接通过 类名.对象 的方式调用,这将不符合程序的标准执行过程,一般是通过方法调用
System.out.println(Hungry.hungry);
}
}
再来看private static final Hungry hungry = new Hungry();其中的static的作用是什么呢?
首先说一下,getHungry方法为什么要用静态修饰,是为了满足"单例类必须给所有其他对象提供这一实例"这一特点,且方便调用。
第一个原因是:那么静态方法只能调用静态成员变量,所以成员变量用static修饰。
第二个原因是:静态修饰的成员变量,只属于类,只有一份且共享,不同的值只在本体上发生改变,满足单例设计模式特点"单例类必须并且只能自己创建自己的唯一实例对象"。就好比上面局的例子:我已经打开了任务管理器,我再去打开任务管理器发现没有多个任务管理器窗口,还是原来的那个任务管理器,而且其中的值只会在一个任务管理器上发生改变。
private static final Hungry hungry = new Hungry();其中的final的作用是什么呢?
final修饰成员变量,那么该变量必须赋值一次,即必须强制要求创建一次对象,此后不可更改,该修饰符使代码更加规范,更加符合饿汉单例模式的代码设计规则。
我们来用以下代码验证结论:
package Demo02;
public class Hungry {//饿汉单例模式
//把创建对象的代码注释掉,IDEA会报错:Variable 'hungry' might not have been initialized
//意思你没有进行初始化赋值,必须要赋值我才不会报错
private static final Hungry hungry /*= new Hungry()*/;
private Hungry() {}
public static Hungry getHungry(){
return hungry;
}
}
private Hungry() {}其中的private的作用是什么呢?
private Hungry() {}是一个构造器,构造器的作用是创建对象,单例模式只允许有一个实例化对象,不能从外部创建对象,所以对构造器进行私有化。
懒汉单例模式
饿汉模式在类创建的同时仅仅在栈中声明,而并未在堆中开辟空间,只有在调用方法时,才会创建对象,这样可以减少内存的占用,但运行速度会变慢(以时间换空间)以下为懒汉单例模式常见代码:
package Demo02;
public class Lazy {//懒汉单例模式
private static Lazy lazy = null;
private Lazy() {}
public static Lazy getlazy() {
if (lazy == null) {
lazy = new Lazy();
}
return lazy;
}
}