彻底搞懂防止破坏单例类模式

发布时间:2020-07-14 17:03:48 作者:wx5deb0084464f6
来源:网络 阅读:119

在优锐课的学习分享中,我们探讨了破坏单例属性的三种主要方法以及如何防止它。分享给大家参考学习。

我们习惯于在需要时在我们的应用程序中使用单例设计模式。 众所周知,在单例设计模式中,我们只能创建一个实例并在整个应用程序中访问它。 但是在某些情况下,它将破坏单例行为。
在三个主要概念中,我们可以打破Java中Singleton类的singleton属性。 在这篇文章中,我们将讨论如何破坏它以及如何防止它。
这是示例Singleton类和SingletonTest类。
单例.

Singleton.Java

package demo1;
public final class Singleton {
    private static volatile Singleton instance = null;
    private Singleton() {
    }
    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

SingletonTest.java

 package demo1;
public class SingletonTest {
    public static void main(String[] args) {
        Singleton object1 = Singleton.getInstance();
        Singleton object2 = Singleton.getInstance();
        System.out.println("Hashcode of Object 1 - " + object1.hashCode());
        System.out.println("Hashcode of Object 2 - " + object2.hashCode());
    }
}

这是输出; 你可以看到它具有与objectOne和objectTwo相同的hashcode :

Hashcode of Object 1 - 1836019240
Hashcode of Object 2 - 1836019240

现在,我们将打破这种模式。 首先,我们将使用Java反射。

反射

Java Reflection是一种API,用于在运行时检查或修改方法,类和接口的行为。 使用Reflection API,我们可以在Singleton类中创建多个对象。 考虑以下示例:
ReflectionSingleton.java

package demo1;
import java.lang.reflect.Constructor;
public class ReflectionSingleton {
    public static void main(String[] args)  {
        Singleton objOne = Singleton.getInstance();
        Singleton objTwo = null;
        try {
            Constructor constructor = Singleton.class.getDeclaredConstructor();
            constructor.setAccessible(true);
            objTwo = (Singleton) constructor.newInstance();
        } catch (Exception ex) {
            System.out.println(ex);
        }
        System.out.println("Hashcode of Object 1 - "+objOne.hashCode());
        System.out.println("Hashcode of Object 2 - "+objTwo.hashCode());
    }
}

这个例子展示了反射如何用Java反射来打破单例模式。 你将获得两个哈希码,如下所示。 它在单例模式上有所突破。

防止单例模式反射

有很多方法可以防止反射API中的Singleton模式,但是最好的解决方案之一是,如果实例已经存在,则在构造函数中引发运行时异常。 在这种情况下,我们无法创建第二个实例。

反序列化

在序列化中,我们可以将字节流的对象保存到文件中或通过网络发送。 假设你先序列化Singleton类,然后再次对该对象反序列化,它将创建一个新实例,因此反序列化将破坏Singleton模式。

以下代码用于说明单反模式如何随反序列化而中断。
为Singleton类实现Serializable接口。

DeserializationSingleton.Java

package demo1;
import java.io.*;
public class DeserializationSingleton {
    public static void main(String[] args) throws Exception {
        Singleton instanceOne = Singleton.getInstance();
        ObjectOutput out = new ObjectOutputStream(new FileOutputStream("file.text"));
        out.writeObject(instanceOne);
        out.close();
        ObjectInput in = new ObjectInputStream(new FileInputStream("file.text"));
        Singleton instanceTwo = (Singleton) in.readObject();
        in.close();
        System.out.println("hashCode of instance 1 is - " + instanceOne.hashCode());
        System.out.println("hashCode of instance 2 is - " + instanceTwo.hashCode());
    }
}

输出如下,你可以看到两个 hashcodes.

hashCode of instance 1 is - 2125039532
hashCode of instance 2 is - 381259350

防止单例模式反序列化

为了克服这个问题,我们需要覆盖Singleton类中的readResolve()方法并返回相同的Singleton实例。 使用以下方法更新Singleton.java。

 protected Object readResolve() { 
           return instance; 
     }

现在,运行上面的DeserializationDemo类并查看输出。

hashCode of instance 1 is - 2125039532
hashCode of instance 2 is - 2125039532

克隆

使用“克隆”方法,我们可以创建原始对象的副本; 如果我们在单例模式中应用克隆,这是同一回事。 它将创建两个实例:一个实例和另一个实例。 在这种情况下,我们将打破Singleton原理,如下面的代码所示。

实施「可克隆」介面,并在上述Singleton类别中覆写clone方法

Singleton.java

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

然后,测试克隆以打破单例。

CloningSingleton.java


public class CloningSingleton {
    public static void main(String[] args) throws CloneNotSupportedException, Exception {
        Singleton instanceOne = Singleton.getInstance();
        Singleton instanceTwo = (Singleton) instanceOne.clone();
        System.out.println("hashCode of instance 1 - " + instanceOne.hashCode());
        System.out.println("hashCode of instance 2 - " + instanceTwo.hashCode());
    }
}

这是输出:

hashCode of instance 1 - 1836019240
hashCode of instance 2 - 325040804

如果我们看到上面的输出,则两个实例具有不同的hashcodes。 这意味着这些实例不相同。

防止单例模式克隆

在上面的代码中,它打破了Singleton原理,即。 e创建了两个实例。 为了克服上述问题,我们需要实现/覆盖clone()方法并从克隆方法中抛出异常CloneNotSupportedException。 如果有人尝试创建Singleton的克隆对象,它将抛出异常,如以下代码所示。

    @Override
    protected Object clone() throws CloneNotSupportedException  {
        throw new CloneNotSupportedException();
    }

现在,我们可以运行loningSingleton类; 在创建单个对象的克隆对象时,它将抛出CloneNotSupportedException。

文章写到这里,如有不足之处,欢迎补充评论.希望这篇文章对你有用!

推荐阅读:
  1. 彻底搞懂 Python 编码
  2. C++单例模式与单例类模板

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

单例类模式 程序员 架构师

上一篇:Solr5.2.1-Cloud-Zookeeper快速搭建

下一篇:Swfit 学习 简单UI

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》