Java 单例模式破坏与修复

破坏单例

实现单例后,按照预期结果应该所有对象都是同一个对象。但是以下有几种情况可以破坏单例的性质。

首先让单例类实现Serializable, Cloneable接口。

通过序列化反射克隆这三种方式破坏单例模式

import java.io.*;
import java.lang.reflect.Constructor;


public class WreckSingleton implements Serializable, Cloneable{
    private static final long serialVersionUID = 1L;

    // 构造方法私有化
    private WreckSingleton(){}

    private static class WreckSingletonFactory{
        private static WreckSingleton singleton = new WreckSingleton();
    }

    // 提供外部调用方法,获取实例
    public static WreckSingleton getInstance() {
        return WreckSingletonFactory.singleton;
    }

    public static void testSerializable(){
        try {
            // 获取实例
            WreckSingleton originSingleton = WreckSingleton.getInstance();
            // 写出对象
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(originSingleton);
            // 写入对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            WreckSingleton serializeSingleton = (WreckSingleton) ois.readObject();
            // 判断两个对象是否相等
            System.out.println(originSingleton == serializeSingleton); // false
        }catch (Exception e){

        }

    }

    public static void testReflect(){
        try {
            WreckSingleton originSingleton = WreckSingleton.getInstance();

            // 反射
            Class<WreckSingleton> clazz = WreckSingleton.class;
// 获取无参构造函数
            Constructor<WreckSingleton> constructor = clazz.getDeclaredConstructor();
// 将私有设置为可见
            constructor.setAccessible(true);
// 用构造器生成实例
            WreckSingleton instance = constructor.newInstance();
// 判断两个对象是否相等
            System.out.println(originSingleton == instance); // false
        }catch (Exception e){

        }

    }

    public static void testClone(){
        WreckSingleton originSingleton = WreckSingleton.getInstance();
// 克隆
        WreckSingleton clone = null;
        try {
            clone = (WreckSingleton) originSingleton.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        System.out.println(originSingleton == clone); // false
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        testSerializable();
        testReflect();
//        testClone();
//
    }

修复破坏

  • 序列化

添加readResolve方法,返回Object

  • 反射

添加全局可见变量如果再次调用构造方法生成实例时,抛出运行时错误

  • 克隆

重写clone方法直接返回单例对象

import java.io.*;
import java.lang.reflect.Constructor;


public class Singleton implements Serializable,Cloneable{
    private static final long serialVersionUID = 1L;

    private static volatile boolean isCreated = false;//默认是第一次创建


    // 构造方法私有化
    private Singleton(){
        if(isCreated) {
            throw new RuntimeException("实例已经被创建");
        }
        isCreated = true;
    }

    private static class TestSingletonFactory{
        private static Singleton singleton = new Singleton();
    }

    // 提供外部调用方法,获取实例
    public static Singleton getInstance() {
        return TestSingletonFactory.singleton;
    }

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return getInstance();
    }

    /**
     * 防止序列化破环
     * @return
     */
    private Object readResolve() {
        return getInstance();
    }

    public static void testSerializable(){
        try {
            // 获取实例
            Singleton originSingleton = Singleton.getInstance();
            // 写出对象
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(originSingleton);
            // 写入对象
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
            Singleton serializeSingleton = (Singleton) ois.readObject();
            // 判断两个对象是否相等
            System.out.println(originSingleton == serializeSingleton); // false
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public static void testReflect(){
        try {
            Singleton originSingleton = Singleton.getInstance();

            // 反射
            Class<Singleton> clazz = Singleton.class;
// 获取无参构造函数
            Constructor<Singleton> constructor = clazz.getDeclaredConstructor();
// 将私有设置为可见
            constructor.setAccessible(true);
// 用构造器生成实例
            Singleton instance = constructor.newInstance();
// 判断两个对象是否相等
            System.out.println(originSingleton == instance); // false
        }catch (Exception e){
            e.printStackTrace();
        }

    }

    public static void testClone(){
        Singleton originSingleton = Singleton.getInstance();
// 克隆
        Singleton clone = null;
        try {
            clone = (Singleton) originSingleton.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        System.out.println(originSingleton == clone); // false
    }
    public static void main(String[] args) throws IOException, ClassNotFoundException {
//        testSerializable();
//        testReflect();
        testClone();
//
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值