笔记--实现单例模式的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条


个人公众号

我的个人公众号已经开通了,正在按计划建设中,以后的文章会第一时间发布在公众号中,同时也给大家准备了亿点学习资料,关注公众号后台发送:学习资料

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

java.util.Man

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值