软件开发如何防止反射,序列化和克隆的单例模式
添加时间:2019-06-24 13:59:38
来源:
反射: 可以导致反射破坏单例类的单例属性,如下例所示:
filter_none
编辑
play_arrow
brightness_4
// Java code to explain effect of Reflection
// on Singleton property
import java.lang.reflect.Constructor;
// Singleton class
class Singleton
{
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
}
public class GFG
{
public static void main(String[] args)
{
Singleton instance1 = Singleton.instance;
Singleton instance2 = null;
try
{
Constructor[] constructors =
Singleton.class.getDeclaredConstructors();
for (Constructor constructor : constructors)
{
// Below code will destroy the singleton pattern
constructor.setAccessible(true);
instance2 = (Singleton) constructor.newInstance();
break;
}
}
catch (Exception e)
{
e.printStackTrace();
}
System.out.println("instance1.hashCode():- "
+ instance1.hashCode());
System.out.println("instance2.hashCode():- "
+ instance2.hashCode());
}
}
输出: -
instance1.hashCode(): - 366712642
instance2.hashCode(): - 1829164700
运行此类之后,您将看到hashCodes不同,这意味着,创建了2个相同类的对象,并且销毁了单例模式。
克服反射问题:为了克服反射引发的问题,使用了枚举,因为java在内部确保枚举值仅实例化一次。由于Java Enum可以全局访问,因此它们可以用于单例。它唯一的缺点是它不灵活,即它不允许延迟初始化。
filter_none
编辑
play_arrow
brightness_4
//Java program for Enum type singleton
public enum GFG
{
INSTANCE;
}
由于枚举没有任何构造函数,因此Reflection无法使用它。枚举有默认的构造函数,我们不能自己调用??它们。JVM在内部处理枚举构造函数的创建和调用。由于枚举不会将其构造函数定义赋予程序,因此我们也无法通过Reflection访问它们。因此,在枚举的情况下,反射不能破坏单身属性。
序列化: - 序列化也可能导致单例类的单例属性破坏。序列化用于转换字节流的对象并保存在文件中或通过网络发送。假设您序列化单例类的对象。然后,如果您反序列化该对象,它将创建一个新实例,从而打破单例模式。
filter_none
编辑
play_arrow
brightness_4
// Java code to explain effect of
// Serilization on singleton classes
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Singleton implements Serializable
{
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
}
public class GFG
{
public static void main(String[] args)
{
try
{
Singleton instance1 = Singleton.instance;
ObjectOutput out
= new ObjectOutputStream(new FileOutputStream("file.text"));
out.writeObject(instance1);
out.close();
// deserailize from file to object
ObjectInput in
= new ObjectInputStream(new FileInputStream("file.text"));
Singleton instance2 = (Singleton) in.readObject();
in.close();
System.out.println("instance1 hashCode:- "
+ instance1.hashCode());
System.out.println("instance2 hashCode:- "
+ instance2.hashCode());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
输出: -
instance1 hashCode: - 1550089733
instance2 hashCode: - 865113938
如您所见,两个实例的hashCode不同,因此单个类有2个对象。因此,这个班不再是单身。
克服序列化问题: -为了克服这个问题,我们必须实现方法readResolve()方法。
filter_none
编辑
play_arrow
brightness_4
// Java code to remove the effect of
// Serialization on singleton classes
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
import java.io.Serializable;
class Singleton implements Serializable
{
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
// implement readResolve method
protected Object readResolve()
{
return instance;
}
}
public class GFG
{
public static void main(String[] args)
{
try
{
Singleton instance1 = Singleton.instance;
ObjectOutput out
= new ObjectOutputStream(new FileOutputStream("file.text"));
out.writeObject(instance1);
out.close();
// deserailize from file to object
ObjectInput in
= new ObjectInputStream(new FileInputStream("file.text"));
Singleton instance2 = (Singleton) in.readObject();
in.close();
System.out.println("instance1 hashCode:- "
+ instance1.hashCode());
System.out.println("instance2 hashCode:- "
+ instance2.hashCode());
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
输出: -
instance1 hashCode: - 1550089733
instance2 hashCode: - 1550089733
以上两个哈希码都相同,因此不会创建其他实例。
克隆: 克隆是一个创建重复对象的概念。使用clone我们可以创建对象的副本。假设,我们停止克隆单个对象,然后它将创建一个副本,即有两个单例类的实例,因此该类不再是单例。
filter_none
编辑
play_arrow
brightness_4
// JAVA code to explain cloning
// issue with singleton
class SuperClass implements Cloneable
{
int i = 10;
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
// Singleton class
class Singleton extends SuperClass
{
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
}
public class GFG
{
public static void main(String[] args) throws CloneNotSupportedException
{
Singleton instance1 = Singleton.instance;
Singleton instance2 = (Singleton) instance1.clone();
System.out.println("instance1 hashCode:- "
+ instance1.hashCode());
System.out.println("instance2 hashCode:- "
+ instance2.hashCode());
}
}
输出: -
instance1 hashCode: - 366712642
instance2 hashCode: - 1829164700
两个不同的hashCode意味着有2个不同的单例类对象。
克服克隆问题: -要克服此问题,请覆盖clone()方法并从克隆方法CloneNotSupportedException中引发异常。现在,每当用户尝试创建单个对象的克隆时,它将抛出异常,因此我们的类仍然是单例。
filter_none
编辑
play_arrow
brightness_4
// JAVA code to explain overcome
// cloning issue with singleton
class SuperClass implements Cloneable
{
int i = 10;
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
// Singleton class
class Singleton extends SuperClass
{
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
@Override
protected Object clone() throws CloneNotSupportedException
{
throw new CloneNotSupportedException();
}
}
public class GFG
{
public static void main(String[] args) throws CloneNotSupportedException
{
Singleton instance1 = Singleton.instance;
Singleton instance2 = (Singleton) instance1.clone();
System.out.println("instance1 hashCode:- "
+ instance1.hashCode());
System.out.println("instance2 hashCode:- "
+ instance2.hashCode());
}
}
输出: -
线程“main”java.lang.CloneNotSupportedException中的异常
在GFG.Singleton.clone(GFG.java:29)
在GFG.GFG.main(GFG.java:38)
现在我们已经停止用户创建单例类的克隆。如果你不想抛出异常,你也可以从clone方法返回相同的实例。
filter_none
编辑
play_arrow
brightness_4
// JAVA code to explain overcome
// cloning issue with singleton
class SuperClass implements Cloneable
{
int i = 10;
@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}
}
// Singleton class
class Singleton extends SuperClass
{
// public instance initialized when loading the class
public static Singleton instance = new Singleton();
private Singleton()
{
// private constructor
}
@Override
protected Object clone() throws CloneNotSupportedException
{
return instance;
}
}
public class GFG
{
public static void main(String[] args) throws CloneNotSupportedException
{
Singleton instance1 = Singleton.instance;
Singleton instance2 = (Singleton) instance1.clone();
System.out.println("instance1 hashCode:- "
+ instance1.hashCode());
System.out.println("instance2 hashCode:- "
+ instance2.hashCode());
}
}
输出: -
instance1 hashCode: - 366712642
instance2 hashCode: - 366712642
现在,由于两个实例的哈希码相同,这意味着它们代表单个实例。
需要软件开发就找我们吧
2021-07
到目前为止,我们已经为我们OracleNetsuite的标题创建了导航栏。完成标题的下一件事是在图像上方包含图像和文本,如下面的屏幕截图所示:让我们再次查看index.html 文件中标题的部分代码。代码中突出显示的部分显示了标题的图像菜单:要完成图像菜单,我们首先需要在 id … [了解更多]
2021-07
响应式网站:响应式网站是旨在适合所有类型的设备并调整网站布局以最适合屏幕尺寸的网站。无需制作任何其他设备版本的网站以适应小型设备。移动网站:移动网站是专为适应手机、平板电脑等特别小的设备屏幕而设计的网站。需要制作网站的桌面版本以适应移动设备特定的桌面屏幕。响应式网站和移动网站的区… [了解更多]
2021-06
OracleNetsuitePython 提供了许多分发 Python 项目的方法。其中一种方法是使用一种称为 Docker 的重要技术。Docker 是一个开源应用程序,允许管理员使用容器创建、管理、部署和复制应用程序。它基本上是一个平台,使开发人员能够通过将应用程序放入容器中… [了解更多]
2021-05
财务负责人戴了两顶帽子:一是遵守法规,以确保公司的行为和会计正确无误,并遵守公司开展业务的不同司法管辖区的法规;二是遵守法规。一种战略,确保公司达到财务里程碑和成功指标。当一家公司上市时,包括通过特殊目的收购公司(SPAC)上市时,这两个角色尤其重要。Oracle NetSuit… [了解更多]
2021-03
公司财务人员中记账人员的工作内容:1、从钉钉中下载审批完成的8种审批类型的单据数据,包含合同付款、费用报销等2、记账人员根据付款的性质及费用归属,把记账分成6种形式:合同付款(工程、成本)、合同付款(其他)、非合同付款(工程、成本)、非合同付款(其他)、费用报销(工程、成本)、费… [了解更多]