Siete formas de crear el modo de una sola columna y usar la reflexión y la serialización para descifrar una sola columna

1. Descripción

1. Conceptos básicos de singleton

Solo habrá un objeto de instancia en el Jvm actual

2. Escenarios de aplicación singleton

1. El archivo de configuración definido en el proyecto 2. El
objeto Servlet es singleton por defecto
3. Grupo de subprocesos, grupo de conexión de base de datos
4. El objeto Bean en Spring es singleton por defecto
5. Implementar el contador del sitio web
6. Marco de caché integrado de Jvm (definir singleton HashMap)
7. Defina la información constante de enumeración

3 / Ventajas y desventajas de Singleton

Ventajas: puede guardar la memoria del montón actual, no necesita nuevos objetos con frecuencia y se puede acceder a ellos rápidamente.
Desventajas: cuando varios subprocesos acceden al mismo objeto singleton, puede haber problemas de seguridad de subprocesos.

Dos, 7 formas de crear el modo de una sola columna

  • Si agrega reflexión para crear + serialización crear , para que los nueve tipos creen una forma (para romper una sola columna recreada)
  • Si agrega el constructor para crear , para los 10 tipos de formas de crear
  • El propósito principal del constructor que usa la modificación privada es evitar el uso directo externo del nuevo objeto para inicializar y cambiar la clase, convirtiéndose en múltiples columnas

1. Hombre vago (cuando al mismo tiempo, hay fallas de seguridad)

package com.xijia;

import java.io.Serializable;

/**
 * 单例模式(懒汉式)
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/5 0005 9:49 
 * @version 1.0.0
 */
public class Singleton01 implements Serializable {

    private static Singleton01 singleton01 = null;

    /**
     * 私有化,禁止new 改对象
     */
    private Singleton01() {
    }

    /**
     * 此创建方法  缺陷: 如果两个线程同时进入该 getInstance()方法,会破坏数据初始化的数据
     * 如果: singleton01为计数器或火车票
     * ----a执行 初始化 singleton01 = 1
     * ----b执行 初始化 singleton01 = 1
     * 实际结果应该为2,但实际结果为1 ,有兴趣可自行模拟
     * @return
     */
    public static Singleton01 getInstance() {
        if (singleton01 == null) {
            singleton01 = new Singleton01();
        }
        return singleton01;
    }

    public static void main(String[] args) {
        // 初始化
        Singleton01 instance1 = Singleton01.getInstance();
        // 直接获取,不初始化, 但是遇到instance1和instance2 的调用同时进入if 条件,部分业务数据将不正确(如计数器,火车票等)
        Singleton01 instance2 = Singleton01.getInstance();
        System.out.println(instance1 == instance2);
    }

}

2. Mecanismo de bloqueo perezoso + sincronizado (no hay fallas de seguridad, pero el rendimiento es bajo)

package com.xijia;

/**
 * 单列模式(懒汉式 + synchronized 锁机制)
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/5 0005 9:58
 * @version 1.0.0
 */
public class Singleton02 {

    private static Singleton02 singleton02;

    private Singleton02() {
    }

    /**
     * 初始化 singleton02, 改方式避免了案例一 计数器重复初始化导致结果错误的问题,但存在一定的缺陷
     * 缺陷:
     * 初始化singleton02 无缺陷
     * 但 获取singleton02 数据时出现缺陷, 当我们获取singleton02时,两个线程同时获取singleton02时,必须排队获取singleton02,这显然是会严重影响性能的
     * @return
     */
    public static synchronized Singleton02 getInstance() {
        if (singleton02 == null) {
            singleton02 = new Singleton02();
        }
        return singleton02;
    }

    public static void main(String[] args) {
        // 初始化singleton02
        Singleton02 instance1 = Singleton02.getInstance();
        // 直接获取,不初始化
        Singleton02 instance2 = Singleton02.getInstance();
        System.out.println(instance1 == instance2);
    }
}

3. Hombre perezoso + cerradura de inspección doble (sin defectos + mejor rendimiento)

package com.xijia;


/**
  * 单列模式(懒汉式 + 双重检验锁)
  * @author wangsong
  * @mail  [email protected]
  * @date  2020/9/5 0005 10:06
  * @version 1.0.0
  */
public class Singleton03 {
    private static Singleton03 singleton03;

    private Singleton03() {
    }

    /**
     * 双重检验锁初始化 singleton03
     * 无缺陷
     * ----  修复案例2的 获取数据需要排队的问题,获取数据直接获取,
     * ----- 如果遇到多个线程同时进入 if ,加锁排队,第一个进入的线程初始化了对象,下一个排队的人进入后判断发现对象已经初始化了,就不重新初始化了
     * @return
     */`在这里插入代码片`
    public static Singleton03 getInstance() {
        // 上锁(创建该对象) 第一次判断
        if (singleton03 == null) {
            synchronized (Singleton03.class) {
                //第二次判断
                if (singleton03 == null) {
                    singleton03 = new Singleton03();
                }
            }
        }
        return singleton03;
    }


    public static void main(String[] args) {
        Singleton03 instance1= Singleton03.getInstance();
        Singleton03 instance2= Singleton03.getInstance();
        System.out.println(instance1==instance2);
    }
}

4. Estilo chino hambriento (variables de uso común y estáticas, las deficiencias no se utilizan y ocupan recursos de memoria)

package com.xijia;


/**
 * 饿汉式
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/5 0005 10:12
 * @version 1.0.0
 */
public class Singleton04 {

    /**
     * 当class文件被加载的时候就创建该对象,常用于创建常量
     */
    public static final Singleton04 singleton04 = new Singleton04();

    private Singleton04() {
    }

    public static void main(String[] args) {
        System.out.println(Singleton04.singleton04 == Singleton04.singleton04);
    }

}

5. Creación de bloques de métodos estáticos (no se usa comúnmente)

package com.xijia;


/**
 * 静态方法区
 * @author wangsong
 * @mail [email protected]
 * @date 2020/9/5 0005 10:14
 * @version 1.0.0
 */
public class Singleton05 {


    private static Singleton05 singleton05 = null;

    private Singleton05() {
    }

    /**
     * 只会初始化一次(或常用的 init方法)
     */
    static {
        System.out.println("当前class被加载");
        singleton05 = new Singleton05();
    }

    public static synchronized Singleton05 getInstance() {
        return Singleton05.singleton05;
    }


    public static void main(String[] args) {
        System.out.println(Singleton05.getInstance() == Singleton05.getInstance());
    }
}

6. Creación de clases internas estáticas (comúnmente utilizado en Android)

package com.xijia;


/**
  * 静态内部类
  * @author wangsong
  * @mail  [email protected]
  * @date  2020/9/5 0005 10:16
  * @version 1.0.0
  */
public class Singleton06 {

    public Singleton06() {
    }

    /**
     *  静态内部类 (安卓常用)
     */
    private static class SingletonHolder {
        private static final Singleton06 singleton06 = new Singleton06();
    }

    /**
     * 获取静态内部类的 singleton06
     * @return
     */
    public static Singleton06 getInstance() {
        return SingletonHolder.singleton06;
    }


    public static void main(String[] args) {
        Singleton06 instance1 = Singleton06.getInstance();
        Singleton06 instance2 = Singleton06.getInstance();
        System.out.println(instance1 == instance2);
    }
}

7. Creación de enumeraciones (seguridad absoluta para subprocesos)

package com.xijia;


/**
 * 枚举方式创建
 * @author wangsong
 * @date 2020/9/5 0005 10:21
 * @return
 * @version 1.0.0
 */
public enum Singleton07 {
    INSTANCE;

    public void addUser() {
        System.out.println("我是枚举,我先天性安全");
    }


    Singleton07() {
        System.out.println(">>>Singleton07无参构造函数执行<<");
    }


    public static void main(String[] args) {
        // 只会执行一次构造函数
        System.out.println(Singleton07.INSTANCE == Singleton07.INSTANCE);
    }
}

Tres, rompe la columna única

1. Reflexión agrietada

public class Test001 {
    public static void main(String[] args) throws Exception {

        // 使用反射机制创建我们的对象
        Class<?> aClass = Class.forName("com.xijia.Singleton01");
        //  getDeclaredConstructor();获取当前类(不包含父类),getConstructor 所有的  包含父类构造函数
        Constructor<?> constructor = aClass.getDeclaredConstructor();
        constructor.setAccessible(true);
        // 走无参构造函数 反射创建对象成功
        Singleton01 instance1 = (Singleton01) constructor.newInstance();
        Singleton01 instance2 = Singleton01.getInstance();
        /**
         * 将输出false, 单列对象 Singleton01 被重复创建, singleton01 在静态区的值被重新初始化,原数据将被破坏
         */
        System.out.println(instance1 == instance2);
    }
}

Inserte la descripción de la imagen aquí

2. Agrietamiento por serialización

/**
 * 序列化破解单列 (当类添加了 implements Serializable 的,都将可以破解单列)
 * @author wangsong
 * @date 2020/9/5 0005 10:26
 * @return
 * @version 1.0.0
 */
public class Test002 {
    public static void main(String[] args) throws Exception {
        // 1.需要将该对象序列化到本地存放
        FileOutputStream fos =  new FileOutputStream("d:/code/user.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        Singleton01 instance1 = Singleton01.getInstance();
        oos.writeObject(instance1);
        oos.close();
        fos.close();
        //2.从硬盘中反序列化对象到内存中
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/code/user.txt"));
        Singleton01 instance2 = (Singleton01) ois.readObject();
        /**
         * 将输出false, 单列对象 Singleton01 被重复创建, singleton01 在静态区的值被重新初始化,原数据将被破坏
         */
        System.out.println(instance1==instance2);

    }
}

Inserte la descripción de la imagen aquí

3. Intente descifrar la enumeración por reflexión (no se puede descifrar)

/**
  * 方式破解单列(无法破解,直接抛出异常)
  * @author wangsong
  * @mail  [email protected]
  * @date  2020/9/5 0005 10:33
  * @version 1.0.0
  */
public class Test004 {
    public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {

        Class<?> aClass = Class.forName("com.xijia.Singleton07");
        /**
         * 直接抛出,Exception in thread "main" java.lang.InstantiationException: com.xijia.Singleton07 异常
         */
        Object o = aClass.newInstance();
    }
}

Inserte la descripción de la imagen aquí

4. Intente serializar y descifrar la enumeración (no se puede descifrar)


/**
 * 序列化破解枚举(先天性安全,无法破解)
 * @author wangsong
 * @date 2020/9/5 0005 10:30
 * @return
 * @version 1.0.0
 */
public class Test003 {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        // 1.将对象序列化存入到本地文件中
        FileOutputStream fos = new FileOutputStream("d:/code/a.txt");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        Singleton07 instance1 = Singleton07.INSTANCE;
        oos.writeObject(Singleton07.INSTANCE);
        oos.close();
        fos.close();

        //2.从硬盘中反序列化对象到内存中
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("d:/code/a.txt"));
        Singleton07 instance2 = (Singleton07) ois.readObject();
        /**
         * 输出true, 枚举类没有被重新创建,原数据绝对安全
         */
        System.out.println(instance1 == instance2);
    }
}

Inserte la descripción de la imagen aquí

  • Parte del contenido anterior proviene de Ant Classroom http://www.mayikt.com/

  • Proyecto personal de código abierto (sistema de gestión de fondo universal) -> https://gitee.com/wslxm/spring-boot-plus2 , puede consultarlo si lo desea

  • Este es el final de este artículo. Si lo encuentra útil, por favor, haga clic en Me gusta o preste atención. Continuaremos actualizando más contenido de vez en cuando ... ¡Gracias por mirar!

Supongo que te gusta

Origin blog.csdn.net/qq_41463655/article/details/108416482
Recomendado
Clasificación