精华内容
下载资源
问答
  • java单例模式的简单应用例子
    2021-02-12 17:38:54

    单例模式:用于保证在程度的运行期间某个类有且只有一个实例

    优势:在于尽可能节约资源

    应用场景:还不太懂,希望懂的前辈们补充

    ————————————————————

    通过修改构造方法的访问权限实现单例模式

    比如package com.lixiyu;

    public class TestExample1{

    public static void main(String[] args){

    System.out.println("创建神马1对象:");

    SHENMA shenma1=SHENMA.getInstance();//创建对象

    shenma1.getName();//输出名字

    System.out.println("创建神马2对象:");

    SHENMA shenma2=SHENMA.getInstance();//创建对象

    shenma2.getName();//输出名字

    System.out.println("创建神马3对象:");

    SHENMA shenma3=SHENMA.getInstance();//创建对象

    shenma3.getName();//输出名字

    }

    }

    这时需要创建一个SHENMA的CLASS类来说明package com.lixiyu;

    public class SHENMA {

    private static SHENMA shenma=null;//声明一个类SHENMA的引用

    private SHENMA(){//将构造方法私有化

    }

    public static SHENMA getInstance(){

    if(shenma==null){

    shenma=new SHENMA();

    }

    return shenma;

    }

    public void getName(){

    System.out.println("这是神马:好东西");

    }

    }

    只需要new一次创建实例就可以解决问题了public static SHENMA getInstance(){

    if(shenma==null){

    shenma=new SHENMA();

    }

    return shenma;

    }

    单例模式还有很多种写法,这只是其中之一,在以后学习里遇到再记录下来。

    更多相关内容
  • java 单例模式的实例详解概念:java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。单例模式有一下特点:1、单例类只能有一个实例。2、单例类必须自己自己创建自己的...

    java 单例模式的实例详解

    概念:

    java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、登记式单例三种。

    单例模式有一下特点:

    1、单例类只能有一个实例。

    2、单例类必须自己自己创建自己的唯一实例。

    3、单例类必须给所有其他对象提供这一实例。

    单例模式确保某个类只有一个实例,而且自行实例化并向整个系统提供这个实例。在计算机系统中,线程池、缓存、日志对象、对话框、打印机、显卡的驱动程序对象常被设计成单例。这些应用都或多或少具有资源管理器的功能。每台计算机可以有若干个打印机,但只能有一个Printer Spooler,以避免两个打印作业同时输出到打印机中。每台计算机可以有若干通信端口,系统应当集中管理这些通信端口,以避免一个通信端口同时被两个请求同时调用。总之,选择单例模式就是为了避免不一致状态,避免政出多头。

    首先看一个经典的单例实现。

    public class Singleton {

    private static Singleton uniqueInstance = null;

    private Singleton() {

    // Exists only to defeat instantiation.

    }

    public static Singleton getInstance() {

    if (uniqueInstance == null) {

    uniqueInstance = new Singleton();

    }

    return uniqueInstance;

    }

    // Other methods...

    }

    Singleton通过将构造方法限定为private避免了类在外部被实例化,在同一个虚拟机范围内,Singleton的唯一实例只能通过getInstance()方法访问。(事实上,通过Java反射机制是能够实例化构造方法为private的类的,那基本上会使所有的Java单例实现失效。此问题在此处不做讨论,姑且掩耳盗铃地认为反射机制不存在。)

    但是以上实现没有考虑线程安全问题。所谓线程安全是指:如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题。显然以上实现并不满足线程安全的要求,在并发环境下很可能出现多个Singleton实例。

    public class TestStream {

    private String name;

    public String getName() {

    return name;

    }

    public void setName(String name) {

    this.name = name;

    }

    //该类只能有一个实例

    private TestStream(){} //私有无参构造方法

    //该类必须自行创建

    //有2种方式

    /*private static final TestStream ts=new TestStream();*/

    private static TestStream ts1=null;

    //这个类必须自动向整个系统提供这个实例对象

    public static TestStream getTest(){

    if(ts1==null){

    ts1=new TestStream();

    }

    return ts1;

    }

    public void getInfo(){

    System.out.println("output message "+name);

    }

    }

    /**

    *

    */

    public class TestMain {

    public static void main(String [] args){

    TestStream s=TestStream.getTest();

    s.setName("张孝祥");

    System.out.println(s.getName());

    TestStream s1=TestStream.getTest();

    s1.setName("张孝祥");

    System.out.println(s1.getName());

    s.getInfo();

    s1.getInfo();

    if(s==s1){

    System.out.println("创建的是同一个实例");

    }else if(s!=s1){

    System.out.println("创建的不是同一个实例");

    }else{

    System.out.println("application error");

    }

    }

    }

    运行结果:

    张孝祥

    张孝祥

    output message 张孝祥

    output message 张孝祥

    创建的是同一个实例

    结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。

    1.饿汉式单例类

    //饿汉式单例类.在类初始化时,已经自行实例化

    public class Singleton1 {

    //私有的默认构造子

    private Singleton1() {}

    //已经自行实例化

    private static final Singleton1 single = new Singleton1();

    //静态工厂方法

    public static Singleton1 getInstance() {

    return single;

    }

    }

    2.懒汉式单例类

    //懒汉式单例类.在第一次调用的时候实例化

    public class Singleton2 {

    //私有的默认构造子

    private Singleton2() {}

    //注意,这里没有final

    private static Singleton2 single=null;

    //静态工厂方法

    public synchronized static Singleton2 getInstance() {

    if (single == null) {

    single = new Singleton2();

    }

    return single;

    }

    }

    3.登记式单例类

    import java.util.HashMap;

    import java.util.Map;

    //登记式单例类.

    //类似Spring里面的方法,将类名注册,下次从里面直接获取。

    public class Singleton3 {

    private static Map map = new HashMap();

    static{

    Singleton3 single = new Singleton3();

    map.put(single.getClass().getName(),single);

    }

    //保护的默认构造子

    protected Singleton3(){}

    //静态工厂方法,返还此类惟一的实例

    public static Singleton3 getInstance(String name) {

    if(name == null) {

    name = Singleton3.class.getName();

    System.out.println("name == null"+"--->name="+name);

    }

    if(map.get(name) == null) {

    try {

    map.put(name,(Singleton3) Class.forName(name).newInstance());

    } catch (InstantiationException e) {

    e.printStackTrace();

    } catch (IllegalAccessException e) {

    e.printStackTrace();

    } catch (ClassNotFoundException e) {

    e.printStackTrace();

    }

    }

    return map.get(name);

    }

    //一个示意性的商业方法

    public String about() {

    return "Hello,I am RegSingleton.";

    }

    public static void main(String[] args) {

    Singleton3 single3 = Singleton3.getInstance(null);

    System.out.println(single3.about());

    }

    }

    如有疑问请留言或者到本站社区交流讨论,感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

    相关文章

    总结

    以上是编程之家为你收集整理的java 单例模式的实例详解全部内容,希望文章能够帮你解决java 单例模式的实例详解所遇到的程序开发问题。

    如果觉得编程之家网站内容还不错,欢迎将编程之家网站推荐给程序员好友。

    本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。

    如您喜欢交流学习经验,点击链接加入交流1群:1065694478(已满)交流2群:163560250

    展开全文
  • Java单例

    2021-03-05 15:29:51
    单例类:主要知识点:1,单例类概念、特点2,三种单例类懒汉,饿汉,双重加锁举例,3,懒汉、饿汉区别以及单例类的总结;1,概念:java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、...

    单例类:

    主要知识点:

    1,单例类概念、特点

    2,三种单例类懒汉,饿汉,双重加锁举例,

    3,懒汉、饿汉区别以及单例类的总结;

    1,概念:java中单例模式是一种常见的设计模式,单例模式分三种:懒汉式单例、饿汉式单例、双重检查加锁单例三种。单例模式有以下特点:1、单例类只能有一个实例。//构造函数为private2、单例类必须自己创建自己的唯一实例。3、单例类必须给所有其他对象提供这一实例。//public方法

    2,三种单例类:

    饿汉式:

    1 public classEagerSingleton {2

    3 private static EagerSingleton instance = newEagerSingleton();4

    5 /**

    6

    7 * 私有默认构造子8

    9 */

    10

    11 privateEagerSingleton(){}12

    13 /**

    14

    15 * 静态工厂方法16

    17 */

    18

    19 public staticEagerSingleton getInstance(){20

    21 returninstance;22

    23 }24

    25 }

    例子中,在这个类被加载时,静态变量instance会被初始化,此时类的私有构造函数会被调用。这时候,单例类的唯一实例就被创建出来了。饿汉式在装载类的时候就创建对象实例。

    饿汉式是空间换时间,当类装载的时候就会创建类的实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断,节省了运行时间。

    懒汉式:

    1 public classLazySingleton {2

    3 private static LazySingleton instance = null;4

    5 /**

    6

    7 * 私有默认构造子8

    9 */

    10

    11 privateLazySingleton(){}12

    13 /**

    14

    15 * 静态工厂方法16

    17 */

    18

    19 public static synchronizedLazySingleton getInstance(){20

    21 if(instance == null){22

    23 instance = newLazySingleton();24

    25 }26

    27 returninstance;28

    29 }30

    31

    懒汉式单例类实现里对静态工厂方法使用了同步化,以处理多线程环境。懒汉式在不急着创建对象实例。会一直等到马上要使用对象实例的时候才会创建,在装载对象的时候不创建对象实例。

    懒汉式是时间换空间,就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间

    由于懒汉式的实现是线程安全的,这样会降低整个访问的速度,而且每次都要判断。

    双重检查加锁:(java5及以上的版本)

    所谓“双重检查加锁”机制,指的是:并不是每次进入getInstance方法都需要同步,而是先不同步,进入方法后,先检查实例是否存在,如果不存在才进行下面的同步块,这是第一重检查,进入同步块过后,再次检查实例是否存在,如果不存在,就在同步的情况下创建一个实例,这是第二重检查。这样一来,就只需要同步一次了,从而减少了多次在同步情况下进行判断所浪费的时间。使用“双重检查加锁”的方式来实现,就可以既实现线程安全,又能够使性能不受很大的影响

    “双重检查加锁”机制的实现会使用关键字volatile,它的意思是:被volatile修饰的变量的值,将不会被本地线程缓存,所有对该变量的读写都是直接操作共享内存,从而确保多个线程能正确的处理该变量。

    1 public classSingleton {2

    3 private volatile static Singleton instance = null;4

    5 privateSingleton(){}6

    7 public staticSingleton getInstance(){8

    9 //先检查实例是否存在,如果不存在才进入下面的同步块

    10

    11 if(instance == null){12

    13 //同步块,线程安全的创建实例

    14

    15 synchronized (Singleton.class) {16

    17 //再次检查实例是否存在,如果不存在才真正的创建实例

    18

    19 if(instance == null){20

    21 instance = newSingleton();22

    23 }24

    25 }26

    27 }28

    29 returninstance;30

    31 }32

    33 }

    这种实现方式既可以实现线程安全地创建实例,而又不会对性能造成太大的影响。它只是第一次创建实例的时候同步,以后就不需要同步了,从而加快了运行速度。

    提示:由于volatile关键字可能会屏蔽掉虚拟机中一些必要的代码优化,所以运行效率并不是很高。因此一般建议,没有特别的需要,不要使用。也就是说,虽然可以使用“双重检查加锁”机制来实现线程安全的单例,但并不建议大量采用,可以根据情况来选用。

    3,饿汉式和懒汉式区别以及总结

    两种区别主要两点

    1、线程安全:

    饿汉式是线程安全的,可以直接用于多线程而不会出现问题,懒汉式就不行,它是线程不安全的,如果用于多线程可能会被实例化多次,失去单例的作用。

    如果要把懒汉式用于多线程,有两种方式保证安全性,一种是在getInstance方法上加同步,另一种是在使用该单例方法前后加双锁。

    2、资源加载:

    饿汉式在类创建的同时就实例化一个静态对象出来,不管之后会不会使用这个单例,会占据一定的内存,相应的在调用时速度也会更快,

    而懒汉式顾名思义,会延迟加载,在第一次使用该单例的时候才会实例化对象出来,第一次掉用时要初始化,如果要做的工作比较多,性能上会有些延迟,之后就和饿汉式一样了。

    结论:由结果可以得知单例模式为一个面向对象的应用程序提供了对象惟一的访问点,不管它实现何种功能,整个应用程序都会同享一个实例对象。

    附:

    线程安全:

    如果你的代码所在的进程中有多个线程在同时运行,而这些线程可能会同时运行这段代码。如果每次运行结果和单线程运行的结果是一样的,而且其他的变量的值也和预期的是一样的,就是线程安全的。或者说:一个类或者程序所提供的接口对于线程来说是原子操作,或者多个线程之间的切换不会导致该接口的执行结果存在二义性,也就是说我们不用考虑同步的问题,那就是线程安全的。

    展开全文
  • JAVA单例模式代码实现

    2020-08-26 00:05:25
    JAVA常见的设计模式之单例模式 懒汉模式 懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间...

    JAVA常见的设计模式之单例模式

    • 懒汉模式

                 懒汉式是典型的时间换空间,也就是每次获取实例都会进行判断,看是否需要创建实例,浪费判断的时间。当然,如果一直没有人使用的话,那就不会创建实例,则节约内存空间(搬运工)。

    标准的懒汉模式

    class LazySingleton {
        // 私有成员属性
        private LazySingleton lazySingleton;
        
        // 私有构造方法
        private LazySingleton() {
        }
        
        // 公共的获取实例方法
        public LazySingleton getLazySingleton() {
            // 如果成员属性为空,则创建实例
            if (lazySingleton == null) {
                lazySingleton = new LazySingleton();
            }
            return lazySingleton;
        }
    }

    单线程环境下,该单例模式只会有一个实例

    public class TestDemo
    {
        public static void main(String[] args) {
            LazySingleton lazySingleton = LazySingleton.getLazySingleton();
            LazySingleton lazySingleton2 = LazySingleton.getLazySingleton();
            System.out.println(lazySingleton == lazySingleton2);
        }
    }

    运行结果:

    多线程模式下,可能会产生多个实例

    public class TestDemo
    {
        public static void main(String[] args) {
            new Thread(() -> {
                LazySingleton lazySingleton = LazySingleton.getLazySingleton();
                System.out.println(lazySingleton);
            }).start();
            new Thread(() -> {
                LazySingleton lazySingleton = LazySingleton.getLazySingleton();
                System.out.println(lazySingleton);
            }).start();
        }
    }

    运行结果:

    初步改进

    class LazySingleton {
        // 私有成员属性
        private static LazySingleton lazySingleton;
    
        // 私有构造方法
        private LazySingleton() {
        }
    
        // 公共的获取实例方法
        public synchronized static LazySingleton getLazySingleton() {
            // 如果成员属性为空,则创建实例
            if (lazySingleton == null) {
                lazySingleton = new LazySingleton();
            }
            return lazySingleton;
        }
    }

    缺点,每次调用方法都会加锁,效率低

    再次改进

    class LazySingleton {
        // 私有成员属性,使用volatile可以保证代码的有序性,防止指令重排
        private volatile static LazySingleton lazySingleton;
    
        // 私有构造方法
        private LazySingleton() {
        }
    
        // 公共的获取实例方法
        // 使用synchronized + 双重确认机制可以保证线程安全,但有可能存在指令重排,会导致创建多个实例
        public static LazySingleton getLazySingleton() {
            if (lazySingleton == null) {
                synchronized (LazySingleton.class) {
                    if (lazySingleton == null) {
                        lazySingleton = new LazySingleton();
                    }
                }
            }
            return lazySingleton;
        }
    }

    静态类部类单例

    /**
     * 由静态内部类持有单例对象,并调用外部类的私有构造器初始化,由外部类调用静态内部类的属性
     * 本质是一个懒汉模式,在类加载时才会初始化对象
     */
    class InnerSingleton implements Serializable {
    
        private static class InnerSingletonHolder {
            private static InnerSingleton innerSingleton = new InnerSingleton();
        }
    
        private InnerSingleton() {
        }
    
        public static InnerSingleton getInnerSingleton() {
            return InnerSingletonHolder.innerSingleton;
        }
    
    }

     静态类不类单例不会有线程安全问题,线程安全由类加载机制担保

    恶汉模式

                 饿汉式是典型的空间换时间,当类装载的时候就会创建类实例,不管你用不用,先创建出来,然后每次调用的时候,就不需要再判断了,节省了运行时间(搬运工)。 

    // 利用类加载机制保证线程安全
    class HungrySingleton {
        private static HungrySingleton hungrySingleton = new HungrySingleton();
    
        private HungrySingleton() {
        }
    
        public static HungrySingleton getHungrySingleton() {
            return hungrySingleton;
        }
    }

     枚举单例模式

    package com.hy.test.singletonDemo;
    
    public enum EnumSingletonDemo {
        INSTANCE;
    
    }
    
    class EnumTest {
        public static void main(String[] args) {
            EnumSingletonDemo instance = EnumSingletonDemo.INSTANCE;
            EnumSingletonDemo instance2 = EnumSingletonDemo.INSTANCE;
            System.out.println(instance == instance2);
        }
    }
    

    运行结果:

    单例模式可能出现的问题(都会用静态类不类单例举例)

    反射攻击

    /**
     * 测试demo
     *
     * @auther Hy
     * @date 2020/8/25
     */
    public class TestDemo {
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            InnerSingleton innerSingleton = InnerSingleton.getInnerSingleton();
            Class clazz = InnerSingleton.class;
            Constructor<InnerSingleton> declaredConstructor = clazz.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            InnerSingleton innerSingleton1 = (InnerSingleton) declaredConstructor.newInstance();
            System.out.println(innerSingleton == innerSingleton1);
        }
    }
    
    /**
     * 由静态内部类持有单例对象,并调用外部类的私有构造器初始化,由外部类调用静态内部类的属性
     * 本质是一个懒汉模式,在类加载时才会初始化对象
     */
    class InnerSingleton implements Serializable {
    
        private static class InnerSingletonHolder {
            private static InnerSingleton innerSingleton = new InnerSingleton();
        }
    
        private InnerSingleton() {
        }
    
        public static InnerSingleton getInnerSingleton() {
            return InnerSingletonHolder.innerSingleton;
        }
    
    }

    运行结果:

    由此可见,反射生成了一个新的对象,不符合单例模式的定义

    解决方法:在私有构造器中添加判断,如果已存在实例对象,抛出异常(也可进行其他操作,根据需求决定)

    优化后的代码如下

    /**
     * 测试demo
     *
     * @auther Hy
     * @date 2020/8/25
     */
    public class TestDemo {
        public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
            InnerSingleton innerSingleton = InnerSingleton.getInnerSingleton();
            Class clazz = InnerSingleton.class;
            Constructor<InnerSingleton> declaredConstructor = clazz.getDeclaredConstructor();
            declaredConstructor.setAccessible(true);
            InnerSingleton innerSingleton1 = (InnerSingleton) declaredConstructor.newInstance();
            System.out.println(innerSingleton == innerSingleton1);
        }
    }
    
    /**
     * 由静态内部类持有单例对象,并调用外部类的私有构造器初始化,由外部类调用静态内部类的属性
     * 本质是一个懒汉模式,在类加载时才会初始化对象
     */
    class InnerSingleton implements Serializable {
    
        private static class InnerSingletonHolder {
            private static InnerSingleton innerSingleton = new InnerSingleton();
        }
    
        private InnerSingleton() {
            // 防止反射攻击,只有恶汉与静态类部类能防止反射攻击
            if (InnerSingletonHolder.innerSingleton != null) {
                throw new RuntimeException("单例模式已存在一个实例");
            }
        }
    
        public static InnerSingleton getInnerSingleton() {
            return InnerSingletonHolder.innerSingleton;
        }
    
    }

     运行结果:

    注意:只有恶汉模式与静态类部类能防止反射攻击

    序列化相关问题

     首先,我们对创建的实例进行序列化,代码如下:

    /**
     * 测试demo
     *
     * @auther Hy
     * @date 2020/8/25
     */
    public class TestDemo {
        public static void main(String[] args) throws IOException {
            InnerSingleton innerSingleton = InnerSingleton.getInnerSingleton();
            // 序列化测试
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("innerTest"));
            oos.writeObject(innerSingleton);
            oos.close();
            // 反序列化
    /*        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("innerTest"));
            InnerSingleton innerSingleton1 = (InnerSingleton) ois.readObject();
            System.out.println(innerSingleton == innerSingleton1);*/
        }
    }
    
    /**
     * 由静态内部类持有单例对象,并调用外部类的私有构造器初始化,由外部类调用静态内部类的属性
     * 本质是一个懒汉模式,在类加载时才会初始化对象
     */
    class InnerSingleton implements Serializable {
    
        // 需要固定序列化版本号id,如果不固定,JVM会根据字段、方法等生成一个序列化ID,并存入对应的序列化文件,反序列化时,
        // 会按照相同规则生成一个序列化版本号进行对比,如果类已经发生了改变,反序列化的版本号会对应不上,反序列化会失败
        private static final long serialVersionUID = 7822769557659839582L;
    
        private static class InnerSingletonHolder {
            private static InnerSingleton innerSingleton = new InnerSingleton();
        }
    
        private InnerSingleton() {
            // 防止反射攻击,只有恶汉与静态类不类能防止反射攻击
            if (InnerSingletonHolder.innerSingleton != null) {
                throw new RuntimeException("单例已存在一个实例");
            }
        }
    
        public static InnerSingleton getInnerSingleton() {
            return InnerSingletonHolder.innerSingleton;
        }
        
    }

    然后,我们进行反序列化,查看反序列化生成的实例跟单例的实例是否是同一个

    /**
     * 测试demo
     *
     * @auther Hy
     * @date 2020/8/25
     */
    public class TestDemo {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            InnerSingleton innerSingleton = InnerSingleton.getInnerSingleton();
            // 序列化测试
    /*        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("innerTest"));
            oos.writeObject(innerSingleton);
            oos.close();*/
            // 反序列化
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("innerTest"));
            InnerSingleton innerSingleton1 = (InnerSingleton) ois.readObject();
            System.out.println(innerSingleton == innerSingleton1);
        }
    }
    
    /**
     * 由静态内部类持有单例对象,并调用外部类的私有构造器初始化,由外部类调用静态内部类的属性
     * 本质是一个懒汉模式,在类加载时才会初始化对象
     */
    class InnerSingleton implements Serializable {
    
        // 需要固定序列化版本号id,如果不固定,JVM会根据字段、方法等生成一个序列化ID,并存入对应的序列化文件,反序列化时,
        // 会按照相同规则生成一个序列化版本号进行对比,如果类已经发生了改变,反序列化的版本号会对应不上,反序列化会失败
        private static final long serialVersionUID = 7822769557659839582L;
    
        private static class InnerSingletonHolder {
            private static InnerSingleton innerSingleton = new InnerSingleton();
        }
    
        private InnerSingleton() {
            // 防止反射攻击,只有恶汉与静态类不类能防止反射攻击
            if (InnerSingletonHolder.innerSingleton != null) {
                throw new RuntimeException("单例已存在一个实例");
            }
        }
    
        public static InnerSingleton getInnerSingleton() {
            return InnerSingletonHolder.innerSingleton;
        }
    
    }

    运行结果:

    由此可见,反序列化创建了一个新的实例

    解决方法:Serializable的源码中给出了提示

    /**
     * 测试demo
     *
     * @auther Hy
     * @date 2020/8/25
     */
    public class TestDemo {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            InnerSingleton innerSingleton = InnerSingleton.getInnerSingleton();
            // 序列化测试
    /*        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("innerTest"));
            oos.writeObject(innerSingleton);
            oos.close();*/
            // 反序列化
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("innerTest"));
            InnerSingleton innerSingleton1 = (InnerSingleton) ois.readObject();
            System.out.println(innerSingleton == innerSingleton1);
        }
    }
    
    /**
     * 由静态内部类持有单例对象,并调用外部类的私有构造器初始化,由外部类调用静态内部类的属性
     * 本质是一个懒汉模式,在类加载时才会初始化对象
     */
    class InnerSingleton implements Serializable {
    
        // 需要固定序列化版本号id,如果不固定,JVM会根据字段、方法等生成一个序列化ID,并存入对应的序列化文件,反序列化时,
        // 会按照相同规则生成一个序列化版本号进行对比,如果类已经发生了改变,反序列化的版本号会对应不上,反序列化会失败
        private static final long serialVersionUID = 7822769557659839582L;
    
        private static class InnerSingletonHolder {
            private static InnerSingleton innerSingleton = new InnerSingleton();
        }
    
        private InnerSingleton() {
            // 防止反射攻击,只有恶汉与静态类不类能防止反射攻击
            if (InnerSingletonHolder.innerSingleton != null) {
                throw new RuntimeException("单例已存在一个实例");
            }
        }
    
        public static InnerSingleton getInnerSingleton() {
            return InnerSingletonHolder.innerSingleton;
        }
    
        // 反序列化时,如果是单例模式,需要重写该方法,返回单例的实例,否则会获取到不同的对象
        Object readResolve() throws ObjectStreamException {
            return InnerSingletonHolder.innerSingleton;
        }
    }

    运行结果:

    因此,在工作中推荐大家使用静态类部类单例模式,可以有效的防止反射攻击与序列化带来的相关问题

    展开全文
  • 单例模式是 Java 中最简单,也是最基础,最常用的设计模式之一。在运行期间,保证某个类只创建一个实例,保证一个类仅有一个实例,并提供一个访问它的全局访问点。下面就来讲讲Java中的N种实现单例模式的写法。 ...
  • 单例模式有 3 个特点: 1、单例类只有一个实例对象; 2、该单例对象必须由单例类自行创建; 3、单例类对外提供一个访问该单例的全局访问点; 单例模式的两种实现形式: 第 1 种:懒汉式单例,可理解为懒加载模式,...
  • 单例即单个实例,在我们生产活动中有些类没必要好多实例存在的。单例模式严格来讲有8种写法。利用类加载器帮助我们实现单例模式。用jvm来保证我们的线程安全。public class Mgr01{private static final Mgr01 ...
  • 单例模式: 单例模式(Singleton)是一种常用的软件设计模式。在应用这个模式时,单例对象的类必须保证只有一个实例存在。许多时候整个系统只需要拥有一个的全局对象,这样有利于我们协调系统整体的行为。比如在某个...
  • Java单例模式例子

    2021-03-14 22:40:04
    Java单例模式例子1. 先写一个Singleton的classpackage stone;public class Singleton {private static Singleton instance;private Singleton() {}public static Singleton getInstance(){if(instance==null)...
  • 单例模式(Singleton)是“四人组”(GoF)设计模式中的一种,归类于创建型模式。从定义上来看,它似乎是非常简单的设计模式,但是当...单例模式单例模式限制了类的实例,并确保在Java虚拟机中有且仅有一个类的实例对象...
  • Java单例模式及开发应用场景

    万次阅读 2018-02-08 19:16:51
    所谓单例,指的就是单实例,有且仅有一个类实例,这个单例不应该由人来控制,而应该由代码来限制,强制单例。 单例有其独有的使用场景,一般是对于那些业务逻辑上限定不能多例只能单例的情况,例如:类似于计数器之...
  • Java单例模式例子

    2017-06-08 12:16:34
    Java 单例模式的实例代码
  • JAVA单例模式详解】

    2021-03-09 21:31:47
    举例:A、B类都想要操作配置文件信息Config.java,所以在方法中都使用了Config con=new Config();但是这是两个不同的对象。对两者的操作互不影响,不符合条件。解决思路:1.不允许其他程序使用new创建该类对象。...
  • * 设计模式:前人总结出来的经验,被后人直接拿来使用.*单例设计模式:一个类只允许有一个对象,将这个对象作为一个全局的访问点,提供出去供大家使用.* 分析:* 1.用户只能有一个对象* 2.全局的访问点:得到的对象就是全局...
  • JAVA单例模式

    2013-11-14 14:47:54
    一、单例模式的介绍 二、单例模式的特点 三、单例模式的应用 四、单例模式使用的注意 五、单例模式的举例
  • Java架构进阶之面试篇 面试这一块,分别有基础、中级、高级等三部分,一步一步检测。 Java基础面试+解析 Java中级开发面试+解析 Java高级面试+解析 Java架构进阶之技能导图篇 筑基 框架 分布式 ...
  • java单例模式的五种实现方式

    千次阅读 2020-05-23 15:56:28
    基于java实现到单例模式
  • Java 单例模式

    2019-10-25 14:15:07
    简单举例看一下 Android 或 Java 中,几个应用了单例模式的场景各自所选择的实现方式: isoChronology,LoggingProxy:饿汉模式; CalendarAccessControlContext:内部静态类; EventBus:双重检查加锁 ...
  • Java单例模式的例子

    2021-02-12 18:51:27
    http://blog.sina.com.cn/s/blog_7e9b4ad701015iqf.html单例模式是一种常见的设计模式单例模式分三种懒汉式单例、饿汉式单例、登记式单例单例模式有一下特点:1、单例类只能有一个实例。2、单例类必须自己创建自己...
  • java单例模式(笔记)

    2022-01-10 15:08:49
    import java.io.Serializable; import java.math.BigDecimal; public class Goods { private static final Goods GOODS = new Goods("123", new BigDecimal(200)); public static Goods getInstall() { return...
  • 单例模式 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一。这种类型的设计模式属于创建型模式,它提供了一种创建对象的最佳方式。 这种模式涉及到一个单一的类,该类负责创建自己的对象,同时确保...
  • 单例模式应用场景

    2016-05-06 14:38:16
    单例模式应用场景
  • JAVA单例设计模式总结及举例 设计模式:前人总结出来的经验,被后人直接拿来使用. 单例设计模式: 一个类只允许有一个对象,将这个对象作为一个全局的访问点,提供出去供大家使用. 分析: 1.用户只能有一个对象...
  • java开发中,我们常用enum实现来单例模式,并且不仅能避免多线程同步问题,而且能确保jvm级别的序列化反序列化的安全性。那么enum类型是如何保证这些呢? 提示:以下是本篇文章正文内容,下面案例可供参考 一、enum...
  • 单例模式的定义: 数学与逻辑学中,singleton定义为“有且仅有一个元素的集合”。 单例模式最初的定义出现...Java单例模式例子 public class Singleton { private Singleton(){ } private static volatile Singleton
  • 一:单例模式简介 • 单例模式,又名单态模式, Singleton。 • 限定某一个类在整个程序运行过程中,只能保留 一个实例对象在内存空间。 • 单例模式是GoF的23种设计模式(Design Pattern)中 经典的一种,...
  • 单例设计模式介绍 所谓类的单例设计模式,就是 采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例, 并且该类只提供一个取得其对象实例的方法(静态方法)。 比如 Hibernate 的 SessionFactory,它...
  • Java单例设计模式

    2020-06-21 12:23:47
    同步方法)代码实现优缺点说明2.5、懒汉式(线程安全,同步代码块)2.6、双重检查代码实现优缺点说明2.7、静态内部类代码实现优缺点说明2.8、枚举代码实现优缺点说明3、单例模式在JDK源码使用举例4、单例模式注意事项和...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 25,124
精华内容 10,049
关键字:

java单例举例

java 订阅