java中的单例模式经常会被问及作为单例的安全性,是否真正的能够实现实例的唯一性。正常情况下我们考虑是可以实现实例的唯一性的,如下单例:
publicclassSingleton{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnthis.INSTANCE;
}
}
上面的单例类可以返回唯一的实例。
但是我们引入(1)反射机制(2)序列化机制之后就会变得不同
一、反射机制的引入来破坏单例模式
下面是一个单例类,我们通过反射机制生成该类的一个实例。
importjava.lang.reflect.Constructor;
publicclassSingleton{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicSingletongetInstance(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//反射机制破坏单例模式
Classclazz=Singleton.class;
Constructorc=clazz.getDeclaredConstructor();
//反射机制使得private方法可以被访问!!!
c.setAccessible(true);
//判断反射生成的对象与单例对象是否相等
System.out.println(Singleton.INSTANCE==c.newInstance());
}
}
此时程序运行结果输出false,可以看出反射机制生成了新的对象,因此反射可以破坏单例模式。
二、序列化机制来破坏单例模式
序列化可以实现从字节码生成对象,因此序列化也有可能破坏单例模式
下面给出一个实现了序列化接口Serializable的单例类,看序列化如何生成单例类的一个实例
importjava.io.ByteArrayInputStream;
importjava.io.ByteArrayOutputStream;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassSingletonimplementsSerializable{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
publicstaticvoidmain(String[]args)throwsException{
//支持java.io.Serializable的对象都可以写入流中
ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(Singleton.INSTANCE);
//根据字节流生成对象
ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
SingletonnewSingleton=(Singleton)ois.readObject();
System.out.println(newSingleton==Singleton.INSTANCE);
}
}
此时程序运行结果输出false,可以看出序列化机制生成了新的对象,因此反序列化的过程可以破坏单例模式。
不过可以通过引入readResolve方法来阻止反序列化过程中生成新的实例
如下
importjava.io.ByteArrayInputStream;
importjava.io.ByteArrayOutputStream;
importjava.io.ObjectInputStream;
importjava.io.ObjectOutputStream;
importjava.io.Serializable;
publicclassSingletonimplementsSerializable{
publicstaticfinalSingletonINSTANCE=newSingleton();
privateSingleton(){
}
privateObjectreadResolve(){
returnINSTANCE;
}
publicstaticvoidmain(String[]args)throwsException{
//支持java.io.Serializable的对象都可以写入流中
ByteArrayOutputStreambos=newByteArrayOutputStream();
ObjectOutputStreamoos=newObjectOutputStream(bos);
oos.writeObject(Singleton.INSTANCE);
//根据字节流生成对象
ByteArrayInputStreambis=newByteArrayInputStream(bos.toByteArray());
ObjectInputStreamois=newObjectInputStream(bis);
SingletonnewSingleton=(Singleton)ois.readObject();
System.out.println(newSingleton==Singleton.INSTANCE);
}
}
此时程序返回true,readResolve方法使得在反序列化的过程中返回单例中的INSTANCE,而不是生成新的实例。
分享到:
相关推荐
1、掌握单例模式的应用场景。 2、掌握 IDEA 环境下的多线程调试方式。 3、掌握保证线程安全的单例模式策略。 4、掌握反射暴力攻击单例解决方案及原理分析。 5、序列化破坏单例的原理及解决方案。 6、掌握常见的...
主要介绍了JAVA破坏单例模式的方式以及避免方法,文中讲解非常细致,代码帮助大家更好的理解和学习,感兴趣的朋友可以了解下
ThreadLocal实现单例模式如何破坏单例如何防止单例被破坏参考文章 单例模式有以下特点: 1、单例类只能有一个实例。 2、单例类必须自己创建自己的唯一实例。 3、单例类必须给所有其他对象提供这一实例。
单例模式的总体概述 单例模式,属于创建型模式,《设计模式》一书对它做了定义:保证一个类仅有一个实例,并提供一个全局访问点...防止序列化破坏单例模式 多种实现方式与比较 线程安全的饿汉模式 public class HungryS
Go 单例模式讲解和代码示例 单例是一种创建型设计模式, 让你能够保证一个类只有一个实例, 并提供一个访问该实例的全局节点。 单例拥有与全局变量相同的优缺点。 尽管它们非常有用, 但却会破坏代码的模块化特性。
作为一种设计模式,单例模式,可以说的设计模式中比较难的。主要涉及到饿汉模式,懒汉模式,线程安全问题,反射攻击,序列化破坏等。
目录单例模式懒汉式单例模式未初始化问题解决Double Check 双重检查方案一:不让第二步和第三步重排序-DoubleCheck方案二:基于类初始化-静态内部类饿汉式饿汉式与懒汉式最大区别序列化破坏单例模式原理枚举单例基于...
o意:两个校验都必须加,如果第二个没有加校验,当两个线程都通过了第一个if校验,此时会有一个...那么这样就破坏了单例。如果不加第一个if校验,那么所有的程序就会串行执行,影响执行效率。所以两个校验都必须存在
深入了解java反射机制的原理,通过反射机制可以破坏单例模式,如何防止通过反射机制拿到单例模式的构造器呢?用枚举类可破
创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。 结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。 行为型模式(11种):策略...
单例模式:某个类只能有一个实例,提供一个全局的访问点。 简单工厂:一个工厂类根据传入的参量决定创建出那一种产品类的实例。 工厂方法:定义一个创建对象的接口,让子类决定实例化那个类。 抽象工厂:创建相关...
1、创建型模式(5种):工厂方法模式,抽象工厂模式,单例模式,建造者模式,原型模式。 2、结构型模式(7种):适配器模式,装饰器模式,代理模式,外观模式,桥接模式,组合模式,享元模式。 3、行为型模式...
单例模式: 而且自行实例化并向整个系统提供这个实 单例模式 单例模式确保某一个类只有一个实例, 例单例模式。单例模式只应在有真正的“单一实例”的需求时才可使用。 结构型模式 6、ADAPTER —在朋友聚会上碰到...
反射是一个非常重要的知识点,在学习Spring 框架时,Bean的初始化用到了反射,在破坏单例模式时也用到了反射,在获取标注的注解时也会用到反射······ 当然了,反射在日常开发中,我们没碰到过多少,至少我没...
单例(Singleton)模式:某个类只能生成一个实例,该类提供了一个全局访问点供外部获取该实例,其拓展是有限多例模式。 原型(Prototype)模式:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新...
严格的单例模式指的是无法通过常规的 alloc init 方法来生成对象,派生出来的子类也不能产生出对象,而只能通过单例的方法获取到对象 FlyweightPattern 享元设计模式的完整实现 享元模式使用共享物件,用来尽可能减少...
角度引导模式单例请参阅。 “modalDialogs”工厂用法有两种不同的示例:带有和不带有 $scope 传递的二级工厂(“confirmation”和“someDialogService”)。 我什至没有尝试创建任何文档,希望这些示例可以提供足够...
21,单例模式:保证一个类仅有一个实例,并提供一个访问它的全局访问点。 22,状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类. 23,策略模式是一种定义一系列算法的方法,从...
单例模式 饿汉式 类加载的时候就会初始化这个实例, JVM保证唯一实例,线程安全, 但是可以通过反射破坏 方式一 public class Singleton1 { private final static Singleton1 INSTANCE = new Singleton1(); private ...