JAVASE-------单例模式
单例模式
单例模式,属于创建类型的一种常用的软件设计模式。通过单例模式的方法创建的类在当前进程中只有一个实例(根据需要,也有可能一个线程中属于单例,如:仅线程上下文内使用同一个实例)
意思讲白了,就是避免线程安全问题,使得类只能有一个对象。同时,这也是一些面试题目,虽然我只是个学生,多学点没得错。
饿汉式单例
不管我们使用者是否需要这个对象,它都上来先给你创建好这个唯的对象。
枚举类型构造
直接上代码看:
@Test
public void fun() {
SEX sex=SEX.FEMALE;
SEX sex1=SEX.FEMALE;
System.out.println(sex==sex1);//堆内存的地址指向都是相同的,说明是同一个对象
}
enum SEX{
MALE,FEMALE;
}
/*
*这个例子说明,不管怎么样,枚举类型的对象只有一个
* */
打印的结果就是true,说明,枚举类型数据就是恶汉式的一种
单例模式的
/*
*上述例子如果不够饿汉
*来看看下面的例子
* */
@Test
public void fun2() {
COLOR.println();
}
enum COLOR{
WHITE("白色"),BLACK("黑色");
private String colorName;
COLOR(String colorName) {
this.colorName=colorName;
}
public static void println() {
System.out.println("枚举被调用");
}
public String toString() {
return name()+colorName;
}
}
其他样式的饿汉式单例模式
不仅如此,不需要用到枚举对象,但是,他直接创建出来,恶汉模式的典型
jdk1.5之前,枚举类型未更新时,传统单例如下:
样式二
①构造器私有化
②用一个全局的静态的常量,来保存这个唯一-的实例对象
class Student{
public static final Student stu=new Student();
private Student() {}//私有化构造器,防止new
}
@Test
public void fun3() {
Student s1=Student.stu;
Student s2=Student.stu;
System.out.println(s1+"--"+s2);
System.out.println(s1==s2);
//运行结果:
//com.test.Student@18769467--com.test.Student@18769467
//true
}
当然,还有一种样式:
样式三
①构造器私有化
②私有化成员的静态变量
③创建静态的方法,返回静态全局变量
class Student{
private static final Student INSTANCE = new Student();//私有化静态常量
private Student(){}//私有化构造器
public static Student getInstance() {
return INSTANCE ;
}
}
懒汉式单例
延迟创建对象,当使用者(调用者)要用到这个对象的时候再去创建
样式一
①构造器私有化
②私有化成员的静态变量(注意final没有了,不需要初始化)
③创建静态的方法,判断后根据情况返回
class LazyClass{
private static LazyClass lazyClass;
//public static final Student INSTANCE = new Student();这是懒汉式
/*
1、 上一步与饿汉式不同不仅仅在于修饰符public和private上
2、更大的不同在于final取消了,final修饰上去就需要new 初始化出来,就不属于懒汉式
*/
private LazyClass(){}//私有化构造器
public synchronized static LazyClass getInstance() {
//return new LazyClass();这是错误的理念 不符合懒汉式的概念
if(lazyClass==null) {
lazyClass=new LazyClass();
}//否则就直接输出啦
return lazyClass;
}
}
线程安全问题的解决
与饿汉式最大的不同就是final修饰的静态成员变量
,这里如果用final修饰,则需要初始化(final的特性),则不符合“需要再创建”
的概念。
同时,需要注意的就是synchronized
的引入,因为多个用户线程涉及进入后lazyClass==null
这个判断也就会导致线程的问题。
当然这里的锁的范围太大了,导致性能有损,优化版如下
public static LazyClass getInstance() {
if(lazyClass==null){
//return new LazyClass();
synchronized(LazyClass.class) {
//这里不能用this,因为static静态资源先加载,this空指向,可以用反射
if(lazyClass==null) {
lazyClass=new LazyClass();
}//否则就直接输出啦
}
}
return lazyClass;
}
其他形式
利用内部类的特性(用到才会创建)
代码如下
class Lazy2Class{
private Lazy2Class() {}
private static class Inner{
private static final Lazy2Class instance=new Lazy2Class();
}
public static Lazy2Class getInstance() {
return Inner.instance;
}
}
内部类和外部类是两个独立的类(通过字节码文件可以看出来),没有被调用的时候,就不会创建
静态内部类不会随着外部类的初始化一 起初始化,而是要在使用到这个静态内部类时才会初始化
本文地址:https://blog.csdn.net/BlackBtuWhite/article/details/107349037