0    重点掌握

0.1  单例模式如何完全安全

首先前提必须是饿汉式单例,才有安全可能性,原因参考设计模式单例模式。

饿汉式单例的代码demo 参见本节2.5

 

0.2  饿汉式和懒汉式区别

参靠设计模式单例模式,一个是类加载时就初始化,一个是不初始化,static静态代码块

 

0.3  如何理解:本节2.2和2.1 对比的优势

工厂方法优势之一,提供了灵活性,不改变其API的前提下,可以改变该类是否应该为Singleton的想法,工厂方法返回唯一实例。

如:Enum工厂类的getInstance返回唯一实例,如果是其他工厂类可以返回非唯一实例。参考本节2.4

 

0.4  破坏单例的因素

1  反射

2  序列化攻击

 

1    课程内容

1.1  Singleton简介

Singleton指仅仅被实例化一次的类。通常代表本质上唯一的组件,如:窗口管理器或文件系统等。

 

1.2  用三种不同方法强化Singleton属性

参见本节2.1,2.2,2.3

 

1.3  三种不同方法优缺点:

  • 公有静态成员为final域:

缺点:享有特权的客户端可以通过AccessibleObject.setAccessible方法,通过反射机制调用构造器。

解决:修改构造器,让它被要求创建第二个实例时抛出异常。

 

  • 公有静态成员为静态工厂方法

缺点:每次被反序列化一个序列化的实例时,都会创建一个新的实例。

解决:实现Serializable接口,申明所有实例域都是瞬时(transient)的,提供readResolve方法。

 

功能上与公有域方法接近,无偿提供序列化机制,绝对防止多次实例化。

 

 

2    代码演练

2.1  实现Singleton方法1:公有静态成员为final域

package com.ddwei.test.core.chapter2.demo22;

//单例
public class Elvis {

    public static final Elvis INSTANCE = new Elvis();

    //私有构造
    private Elvis(){

    }

    public void method(){

    }


}

 

 

2.2  实现Singleton方法2:公有静态成员为静态工厂方法

package com.ddwei.test.core.chapter2.demo21;

/**
 * 工厂方法生成单例
 * 相比第一种,优势:
 * 1    改变了灵活性,不改变api的前提下就可以改变该类是否成为Singleton(它提供了更多的灵活性,在不改变api的前提下,我们可以轻易地自由调整这个类是否是singleton。工厂方法返回该类的唯一实例,但它很容易修改成别的样子,例如为每个调用该方法的线程提供唯一实例。)
 * 2    与泛型(27条)有关,public域的方法比较简单
 * @author weidoudou
 * @date 2022/4/13 8:24
 **/
public class Elvis {

    private static final Elvis INSTANCE = new Elvis();

    private Elvis(){

    }

    public static Elvis getINSTANCE() {
        return INSTANCE;
    }

    public void method(){

    }
}

 

 

2.3  只需要编写包含单元素的枚举类型,实现Singleton

package com.ddwei.test.core.chapter2.demo25;

public enum Elvis {
    INSTANCE;
    public void leaveTheBuilding(){
        
    }
}

 

 

 

 

2.4  只需要编写包含单元素的枚举类型,实现Singleton 扩展(可能不适用)

部分参考自:https://blog.csdn.net/m0_38130105/article/details/84284687

单例类:

package com.ddwei.test.core.chapter2.demo24;

public class SingletonClass {
}

 

Enum类:

package com.ddwei.test.core.chapter2.demo24;

//单例
public enum Elvis {

    INSTANCE;

    private SingletonClass instance;

    Elvis(){
        instance = new SingletonClass();
    }

    public SingletonClass getInstance(){
        return instance;
    }
    public void method(){

    }


}

 

2.5  如何完全保证单例类不被破坏

package com.ddwei.test.core.chapter2.demo23;

//单例
public class Elvis {

    public static final Elvis INSTANCE;

    static {
        INSTANCE = new Elvis();
    }

    /**
     *  1   构造方法私有,针对外部对象直接new 对象,破坏单例的处理
     *  2   饿汉模式,构造方法做非空判断, 针对通过反射攻击,破坏单例的处理
     * @author weidoudou
     * @date 2022/4/13 20:30
     * @param
     * @return null
     **/
    //私有构造
    private Elvis() {
        if(INSTANCE!=null){
            throw new RuntimeException("单例构造器禁止反射");
        }
    }

    public void method(){

    }

    /**
     * 3    针对序列化和反序列化 生成对象处理,破坏单例的处理
     * @author weidoudou
     * @date 2022/4/13 20:29
     * @param
     * @return java.lang.Object
     **/
    private Object readResolve(){
        return INSTANCE;
    }


}

 

 

 

 

 

posted on 2022-02-18 07:06  菜鸟乙  阅读(32)  评论(0编辑  收藏  举报