zoukankan      html  css  js  c++  java
  • 笔记--实现单例模式的3种简单方式

    实现单例模式的3种简单方式

    我们知道,在面向对象里面,类和对象一般是一对多的关系。一个类可以被实例化为多个对象,但是在我们开发过程中,有些地方要求我们必须使用使用同一个对象,也就是我们多次实例化一个类,得到的是同一个对象,这便是设计模式中的单例模式。

    前两种实现思路比较简单,就是将构造器私有化,暴露公有的静态成员。

    方式一:公有的静态成员为实例

    public class Student{
    
        //导出公用的静态成员
        public static final Student INSTANCE = new Student();
    
        //私有化构造器
        private Student(){};
    }
    

    因为我们使用final对INSTANCE进行修饰,因此它仅仅可以被实例化一次,保证全局唯一。

    方式二:共有的静态成员为静态工厂方法

    public class Student{
    
        private static final Student INSTANCE = new Student();
    
        //共有的静态工厂方法
        public static Student getInstance(){
            return INSTANCE;
        }
        //私有化构造器
        private Student(){};
    }
    

    相对于方式一,方式二具有如下优势:

    • 灵活可以被改为每个线程返回一个唯一实例

    • 可以编写泛型单例工厂

    • 可以使用Java8之后的方法引用 Student::getInstance

    没有上述要求的,推荐方式一

    两种方式都无法避免被攻击者使用反射机制来调用私有的构造方法。

    解决方案是在构造器中在被第二次实例化时抛出异常

    无论是使用方式一还是方式二,当我们的单例是需要变为可序列化的时候,不能仅仅是使用implements Serializable就感觉万事大吉了,否则在每次反序列化时都会创建新的实例,也将不再是单例模式了。要想继续保证单例,我们必须实现readResolve()方法,如下:

    import java.io.Serializable;
    
    public class Student implements Serializable{
    
        private static final Student INSTANCE = new Student();
    
        //共有的静态工厂方法
        public static Student getInstance(){
            return INSTANCE;
        }
        //私有化构造器
        private Student(){};
    
        private Object readResolve(){
            return INSTANCE;
        }
    }
    

    再进行反序列化时,会创建一个Student的新实例,这个实例并非是之前的INSTANCE实例。而对于正确实现了readResolve()方法的类,在反序列化完成之后,会将readResolve()方法返回的实例替换掉反序列化生成的新实例,取代因为反序列化而产生的新对象。指向新对象的引用不再保留,因此立即会变为被GC回收的对象。这样就保证了实例的唯一性。

    方式三:声明一个包含单个元素的枚举类型

    public enum Student{
    
        INSTANCE;
    
        public void otherMethod(){}
     
    }
    

    这种方式最简洁,提供序列化机制,在复杂序列化或者反射攻击时都可以防止多次实例化。当Student需要继承父类时,此方法不宜使用。

    记录于2020年4月29日21:29:35 阅读《Effective Java》第3条

  • 相关阅读:
    【Android UI设计与开发】第17期:滑动菜单栏(二)开源项目SlidingMenu的示例
    [Usaco2008 Dec]Patting Heads
    Hibernate(六)——多对多关联映射
    2017第2周一小程序
    2017第一周日
    2017第一周六
    无论你如何努力,总会有人讨厌你
    word使用技巧-批量删除图片技巧
    Web跨域问题总结
    JAVA语言的本质优势
  • 原文地址:https://www.cnblogs.com/erkye/p/12804941.html
Copyright © 2011-2022 走看看