23种设计模式

时间:2021-03-08 01:08:47

参考链接:

1. 单例模式

参考链接:

1.1 饿汉式单例

 package com.study.singleton;
 ​
 /**
  * @ClassName HungryMan
  * @Description 饿汉式单例模式【不安全】
  * @Author Jiangnan Cui
  * @Date 2023/3/20 22:24
  * @Version 1.0
  */
 public class HungryMan {
     /**
      * 缺点:类加载期间就创建对象,容易造成资源浪费。即:当该类中放置了很多资源时,最开始加载可能会浪费空间,因为加载了也不使用。
      */
     private byte[] data1 = new byte[1024*1204];
     private byte[] data2 = new byte[1024*1204];
     private byte[] data3 = new byte[1024*1204];
     private byte[] data4 = new byte[1024*1204];
     private byte[] data5 = new byte[1024*1204];
 ​
     /**
      * 私有构造方法限制产生多个对象
      */
     private HungryMan() {
     }
 ​
     /**
      * 最开始就创建对象,保证只有一个对象
      */
     private static final HungryMan HUNGRY_MAN = new HungryMan();
 ​
     /**
      * 通过该方法获得实例对象
      * @return
      */
     public static HungryMan getInstance(){
         return HUNGRY_MAN;
     }
 }
 ​

1.2 懒汉式单例

 package com.study.singleton;
 ​
 /**
  * @ClassName LazyMan
  * @Description 懒汉式单例模式:用的时候再创建【不安全】  
  *              单线程下安全,多线程下存在并发安全问题
  * @Author Jiangnan Cui
  * @Date 2023/3/20 22:33
  * @Version 1.0
  */
 public class LazyMan {
     /**
      * 私有构造方法限制产生多个对象
      */
     private LazyMan(){
         // 此处为了测试多线程并发安全问题
         System.out.println(Thread.currentThread().getName() + " is ok");
     }
 ​
     private static LazyMan lazyMan = null;
 ​
     /**
      * 通过该方法获得实例对象
      * @return
      */
     public static LazyMan getInstance(){
         if (lazyMan == null) {
             lazyMan = new LazyMan();
         }
         return lazyMan;
     }
 ​
     public static void main(String[] args) {
         // 多线程并发时存在线程安全问题
         for (int i = 0; i < 10; i++) {
             new Thread(()->{
                 LazyMan.getInstance();
             }).start();
         }
         /**
          * 输出的一个结果举例:
          * Thread-0 is ok
          * Thread-3 is ok
          * Thread-2 is ok
          * Thread-1 is ok
          */
     }
 }
 ​

1.3 懒汉式单例-DCL

 package com.study.singleton;
 ​
 import com.sun.org.apache.bcel.internal.generic.I2B;
 ​
 import java.lang.reflect.Constructor;
 import java.lang.reflect.Field;
 ​
 /**
  * @ClassName LazyMan2
  * @Description 懒汉式单例模式+双重锁校验优化+防止指令重排:DCL懒汉式【不安全】】
  *              解决多线程下存在并发安全问题
  * @Author Jiangnan Cui
  * @Date 2023/3/20 22:33
  * @Version 1.0
  */
 public class LazyMan2 {
     private static boolean secret = false;// 红绿灯
 ​
     /**
      * 私有构造方法限制产生多个对象
      */
     private LazyMan2(){
         // 解决反射破坏单例问题
         synchronized (LazyMan2.class) {
             if (secret == false) {
                 secret = true;
             } else {
                 throw new RuntimeException("不要试图使用反射破坏异常!");
             }
         }
         // 此处为了测试多线程并发安全问题
         System.out.println(Thread.currentThread().getName() + " is ok");
     }
 ​
     /**
      * 加volatile防止指令重排
      */
     private volatile static LazyMan2 lazyMan2 = null;
 ​
     /**
      * 通过该方法获得实例对象
      * @return
      */
     public static LazyMan2 getInstance(){
         if (lazyMan2 == null) {
             synchronized (LazyMan2.class) {
                 if (lazyMan2 == null) {
                     /**
                      * new对象的过程中,不是一个原子性操作
                      * 1.分配内存空间
                      * 2.执行构造方法,初始化对象
                      * 3.把这个对象指向这个空间
                      *
                      * CPU指令重排:1、3、2,此时lazyMan2还没有完成构造,需要加volatile保证指令不重排
                      */
                     lazyMan2 = new LazyMan2();
                 }
             }
         }
         return lazyMan2;
     }
 ​
     public static void main(String[] args) throws Exception {
         /**
          * 反射可以破坏单例
          */
 //        LazyMan2 instance1 = LazyMan2.getInstance();
 ​
         // 2.再次调用反射:获取字段,无视私有
         Field secret = LazyMan2.class.getDeclaredField("secret");
         secret.setAccessible(true);//无视私有构造器
 ​
         // 1.利用反射
         Constructor<LazyMan2> declaredConstructor = LazyMan2.class.getDeclaredConstructor(null);
         // 无视私有构造器
         declaredConstructor.setAccessible(true);
         // 创建新对象
         LazyMan2 instance1 = declaredConstructor.newInstance();
 ​
         // 3.重新设置
         secret.set(instance1, false);
 ​        // 再次利用反射创建对象
         LazyMan2 instance2 = declaredConstructor.newInstance();
 ​
         System.out.println("instance1 = " + instance1);
         System.out.println("instance2 = " + instance2);
     }
 }
 ​

1.4 静态内部类

 package com.study.singleton;
 ​
 /**
  * @ClassName StaticInnerClass
  * @Description 静态内部类单例模式【不安全】
  * @Author Jiangnan Cui
  * @Date 2023/3/20 23:31
  * @Version 1.0
  */
 public class StaticInnerClass {
     private StaticInnerClass(){
     }
 ​
     public static StaticInnerClass getInstance(){
         return InnerClass.STATIC_INNER_CLASS;
     }
 ​
     public static class InnerClass {
         private static final StaticInnerClass STATIC_INNER_CLASS = new StaticInnerClass();
     }
 }
 ​

1.5 枚举

 package com.study.singleton;
 ​
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 ​
 /**
  * @ClassName SingleEnum
  * @Description enum本身也是一个class类,jdk 1.5就有了
  * @Author Jiangnan Cui
  * @Date 2023/3/20 23:18
  * @Version 1.0
  */
 public enum SingleEnum {
     INSTANCE;
     public SingleEnum getInstance(){
         return INSTANCE;
     }
 }
 ​
 class Test{
     public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
         SingleEnum instance1 = SingleEnum.INSTANCE;
         Constructor<SingleEnum> declaredConstructor = SingleEnum.class.getDeclaredConstructor(String.class, int.class);//注意此处并不是无参构造方法,实际有String、int两个参数,要通过反编译工具jad.exe才能验证
         declaredConstructor.setAccessible(true);
 //        SingleEnum instance2 = SingleEnum.INSTANCE;
         SingleEnum instance2 = declaredConstructor.newInstance();
         System.out.println("instance1 = " + instance1);
         System.out.println("instance2 = " + instance2);
 ​
     }
 }
 ​
 // Exception in thread "main" java.lang.IllegalArgumentException: Cannot reflectively create enum objects
     at java.lang.reflect.Constructor.newInstance(Constructor.java:417)
     at com.study.singleton.Test.main(SingleEnum.java:26)
 ​

javap -p 类名.class反编译: 

23种设计模式 jad.exe反编译结果:

23种设计模式

 

待完善