【JAVA】:用枚举法实现单例设计模型

2020/5/26 Java

# 用枚举法实现单例设计模型

       接着上一篇博客写到的几种设计形式下的单例设计模型,上一篇写到的分别由懒汉式(线程不安全),懒汉式(线程安全),饿汉式,双检锁/双重校验锁,登记式/静态内部类,其中的枚举法是放在这里写。

一、破解各个设计形式的单例设计模型。

(1)采用Java反射机制破解单例设计模型(枚举除外)

       下面以内部静态类为例子

public class Demo5 {
	//内部静态类
    private static class Demo6{
    	private static final Demo5 demo=new Demo5();
    }
    private Demo5(){}
    public void sayHello(){
    	System.out.println("登记式/静态内部类:Hello,CSDN");
    }
    public static final Demo5 getdemo(){
    	return Demo6.demo;
    }
    public static void main(String[] args) throws Exception {
        System.out.println("正常获取实例化对象");
		Demo5 demo=Demo5.getdemo();
		Demo5 demo1=Demo5.getdemo();
		System.out.println(demo.hashCode());
		System.out.println(demo1.hashCode());
	    
	    
	    System.out.println("通过Java反射机制获取实例化对象");
		Class<?> c=Class.forName("entity.Demo5");
		Constructor con=c.getDeclaredConstructor(null);
		//true表示反射对象应该在使用时抑制Java语言访问检查,反则为false
		con.setAccessible(true);
		Demo5 d1=(Demo5) con.newInstance();
		Demo5 d2=(Demo5) con.newInstance();
		System.out.println(d1.hashCode());
		System.out.println(d2.hashCode());
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

输出结果: 在这里插入图片描述 理论上输出的对象应该一样,但实际输出俩个不同的对象

解决方法:

    这里提供只提供懒汉式的解决方法

    //在构造方法里面添加一个判断
	  private Demo2(){//构造方法私有化
		  if(demo!= null){
	            throw new RuntimeException();
	        }
	  }
1
2
3
4
5
6

(2)反序列化破解单例设计模型(枚举除外)

前提是该类应该继承Serializable接口        下面以内部静态类为例子

public class Text {
  public static void main(String[] args) throws Exception {
	  Demo5 d1=Demo5.getdemo();
	  Demo5 d2=Demo5.getdemo();
	  System.out.print("反序列化前对象为:");
	  System.out.print(d1.hashCode()+" ");
	  System.out.println(d2.hashCode());
	  
	  //将对象d1写入文件中
	  FileOutputStream fos=new FileOutputStream("e:"+File.separator+"mldn.txt");
	  ObjectOutputStream oos=new ObjectOutputStream(fos);
	  oos.writeObject(d1);
	  oos.close();
	  fos.close();
	  
	  //从文件中读取对象d1
	  ObjectInputStream ois=new ObjectInputStream(new FileInputStream("e:"+File.separator+"mldn.txt"));
	  Demo5 d3=(Demo5) ois.readObject();
      System.out.println("反序列化后对象为:"+d3.hashCode());//s3是一个新对象
	}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

输出结果: 在这里插入图片描述 理论上反序列化后对象应该还是一样当实际不是。

解决方法:

//在该类添加该方法
    private Object readResolve() throws ObjectStreamException{
        return Demo6.demo;
      }
1
2
3
4

处理后: 在这里插入图片描述

二、枚举法实现单例设计模型

枚举

public enum  Demo6 {
    INSTANCE;
    public Demo6 getInstance(){
        return INSTANCE;
    }
}
1
2
3
4
5
6

具体类

public class User {
    //私有化构造函数
    private User(){ }
 
    //定义一个静态枚举类
    static enum SingletonEnum{
        //创建一个枚举对象,该对象天生为单例
        INSTANCE;
        private User user;
        //私有化枚举的构造函数
        private SingletonEnum(){
            user=new User();
        }
        public User getInstnce(){
            return user;
        }
    }
 
    //对外暴露一个获取User对象的静态方法
    public static User getInstance(){
        return SingletonEnum.INSTANCE.getInstnce();
    }
    public static void main(String [] args) throws Exception{
        System.out.println(User.getInstance());
        System.out.println(User.getInstance());
        System.out.println(User.getInstance()==User.getInstance());    
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28

输出结果: 在这里插入图片描述