这种情况我们可以使用readResolve方法来防止。 private Object readResolve(){.....} ...ObjectInputStream 会检查对象的class是否定义了readResolve方法。如果定义了,将由readResolve方法指定返回的对象。...因为我们有定义readResolve()方法,desc通过invokeReadResolve(Object obj)方法调用readResolve()方法获取单例对象instance,将他赋值给rep...6.第一次实例化完成后,通过反射寻找该单例类中的readResolve()方法,没有则直接返回obj对象。这就是我们对没有readResolve()方法的类进行序列化后生成不同对象的原因。...7.因为我们有定义readResolve()方法,desc通过invokeReadResolve(Object obj)方法调用readResolve()方法获取单例对象instance,将他赋值给rep
readResolve() 方法 public class User implements Serializable { private static final long serialVersionUID...userName; } public String getPassword() { return password; } public Object readResolve...return "User [userName=" + userName + ", password=" + password + "]"; } } 我们在 User 类中添加了一个 readResolve...User [userName=zhangsan, password=123456] 相同的实例 无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve...实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。 ----
如果单例模式的类加上了implements Serializable, 就多了一种创建实例的途径.readResolve特性允许你用readObject创建的实例代替另一个实例....对于一个正在被反序列化的对象, 如果它的类定义了一个readResolve方法, 并且具备正确的声明, 那么在反序列化之后, 新建对象上的readResolve方法就会被调用....在这个特性的绝大多数用法中, 指向新建对象的引用不需要再被保留, 因此立即成为垃圾回收的对象.可以利用readResolve方法保证单例模式. -> 方法忽略被反序列化的对象, 只返回该类初始化时创建好的那个实例....如果依赖readResolve进行实例控制, 带有对象引用类型的所有实例域都必须声明为transient的.从历史上来看, readResolve方法被用于所有可序列化的实例受控(instance-controlled...在外围类中添加writeReplace方法. -> 产生代理类实例.外围类中添加readObject方法. -> 防止伪造.代理类中提供readResolve方法, 返回一个逻辑上相当的外围类的实例.
readResolve()方法 在Java规范中有关于readResolve()方法的介绍: 对于可序列化的和外部化的类,readResolve() 方法允许一个类可以替换/解析从流中读取到的对象。...通过实现 readResolve 方法,一个类就可以直接控制反序列化后的实例以及类型。...定义如下: ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException; readResolve 方法会在...ObjectInputStream 会检测类是否定义了 readResolve 方法。 如果 readResolve 方法定义了,会调用该方法用于指定从流中反序列化后作为返回的结果对象。...所以我们可以覆盖 readResolve 方法来解决序列化破坏单例的问题: 类 SingletonZCloneSerializableReadResolve 增加 readResolve 方法: /**
To maintain the singleton guarantee, you have to declare all instance fields transient and provide a readResolve...To prevent this, add this readResolve method to the Elvis class: 为了使上面方法实现的单例类可序列化(第11章),仅仅在它的声明中实现Serializable...为了保证单例性,你必须将所有的实例变量声明为transient并提供一个readResolve方法(Item 77)。...为了防止这种情况发生,要在Elvis类中添加readResolve方法: // readResolve method to preserve singleton property private...Object readResolve() { // Return the one true Elvis and let the garbage collector //
防止序列化破坏单例模式 先给出解决方案,然后再具体分析原理: 只要在Singleton类中定义readResolve就可以解决该问题: code 4 ?...hasReadResolveMethod:如果实现了serializable 或者 externalizable接口的类中包含readResolve则返回true invokeReadResolve:通过反射的方式调用要被反序列化的类的...readResolve方法。...所以,原理也就清楚了,主要在Singleton中定义readResolve方法,并在该方法中指定要返回的对象的生成策略,就可以方式单例被破坏。 总结 在涉及到序列化的场景时,要格外注意他对单例的破坏。
readResolve和writeReplace 如果class中的字段比较多,而这些字段都可以从其中的某一个字段中自动生成,那么我们其实并不需要序列化所有的字段,我们只把那一个字段序列化就可以了,其他的字段可以从该字段衍生得到...readResolve和writeReplace就是序列化对象的代理功能。...log.info("writeReplace {}",this); return new CustUserV3Proxy(this); } } 然后在Proxy对象中,需要实现readResolve...加上一个readResolve方法就可以了: protected final Object readResolve() throws NotSerializableException {...return INSTANCE; } 在这个readResolve方法中,我们返回了INSTANCE,以确保其是同一个对象。
hasReadResolveMethod:若实现了serializable/externalizable接口的类中包含readResolve,则返回true invokeReadResolve:通过反射调用要被反序列化的类的...readResolve方法 3.2 解决方案 在Singleton类中定义readResolve即可: ?
= null); } 可以看到这是一个反射有关的方法,作用是:如果表示的类是实现了serializable/externalizable的,并定义一个符合的readResolve方法则返回true,否则...那么可能有人会有疑问,为什么这个方法名字是readResolve(),而不是其他的呢?...", null, Object.class); 这个代码中就规定了“readResolve”方法的名字,然后上面那个反射方法就是readResolveMethod.invoke(obj, (Object...所以方法名字就是“readResolve”。...那么在反射中调用了我们在单例中定义的“readResolve”方法,这个方法返回了我们已经创建的单例实例,所以读取的类就成了我们在单例中创建的类,而不是上面三目运算创建的新的实例。 好了!
我们,可以通过单例类中,增加一个readResolve()方法里面直接返回INSTANCE即可。...private Object readResolve() { return INSTANCE; } 单例类成如下样子: ?...判断是否有readResolve方法 ? 我们有方法 ? ? 通过反射调用单例中的readResolve()方法, ?...同样,内部Holder类和双重检查锁D.C.L也需要增加readResolve()方法解决。 内部Holder类 ? ? 双重检查锁D.C.L ? ?...所以,我们写单例: 不要实现Cloneable接口 如果有序列化要求,则需要增加readResolve()方法防止破坏 本文,我们还未对枚举实现的单例进行破坏尝试。请大家可以先思考一下?
object KSingleton : Serializable {//实现Serializable序列化接口,通过私有、被实例化的readResolve方法控制反序列化 fun doSomething...() { println("do some thing") } private fun readResolve(): Any {//防止单例对象在反序列化时重新生成对象...return KSingleton//由于反序列化时会调用readResolve这个钩子方法,只需要把当前的KSingleton对象返回而不是去创建一个新的对象 } } //...() { return INSTANCE;//可以看到readResolve方法直接返回了INSTANCE而不是创建新的实例 } static {//静态代码块初始化KSingleton...然而为了让开发者能够控制反序列化,提供一个特殊的钩子方法那就是readResolve方法,这样一来我们只需要在readResolve直接返回原来的实例即可,就不会创建新的对象。
修改后的单例模式 // 使用线程同步创建,防止进程切换重复创建线程, // 设置volatile关键字修饰,使读取singleton对象时能够获取最新状态 // 修改构造方法,防止反射创建对象 // 修改readResolve...singleton = new Singleton2(); } } return singleton; } private Object readResolve
testRe(){ this.ddd=10; this.aaa=60; this.ccc=null; } private Object readResolve...() { System.out.println("readResolve exec..."); return this; } public void t(...this.ddd = 10.0D; this.aaa = 60.0D; this.ccc = null; } private Object readResolve...() { System.out.println("readResolve exec..."); return this; } public void t
防止序列化破坏单例模式 先给出解决方案,然后再具体分析原理: 只要在Singleton类中定义readResolve就可以解决该问题: import java.io.Serializable;...} } return singleton; } private Object readResolve...rep); } } hasReadResolveMethod:如果实现了serializable 或者 externalizable接口的类中包含readResolve...则返回true invokeReadResolve:通过反射的方式调用要被反序列化的类的readResolve方法。...所以,原理也就清楚了,主要在Singleton中定义readResolve方法,并在该方法中指定要返回的对象的生成策略,就可以防止单例被破坏。
getInstance() { return InnerClass.singletonStaticInnerSerialize; } // protected Object readResolve...() { // System.out.println("调用了readResolve方法"); // return InnerClass.singletonStaticInnerSerialize...解决办法就是在反序列化中使用readResolve()方法,将上面的注释代码去掉,再次运行: 865113938 调用了readResolve方法 865113938123 问题来了,readResolve...()方法到底是何方神圣,其实当JVM从内存中反序列化地”组装”一个新对象时,就会自动调用这个 readResolve方法来返回我们指定好的对象了, 单例规则也就得到了保证。...readResolve()的出现允许程序员自行控制通过反序列化得到的对象。
我们需要做的是,在类中加上 readResolve() 这个方法,返回实例。...public static Singleton getInstance() { return INSTANCE; } // 看这里 public Object readResolve...因为在反序列化的时候,JVM 会自动调用 readResolve() 这个方法,我们可以在这个方法中替换掉从流中反序列化回来的对象。...这个方法完整的描述是这样的: ANY-ACCESS-MODIFIER Object readResolve() throws ObjectStreamException; 总结 文中没有示例说反序列化在...enum 类自带这种特殊光环,不用写 readResolve() 方法就可以自动防止反序列化方式对单例的破坏。
readResolve 为什么可以解决序列化破坏单例的问题? 我们通过查看源码中一些关键的步骤,就可以解决心中的疑惑。 我们思考一下,序列化和反序列化的过程中,哪个流程最有可能有操作空间。...发现它最后就是为了返回我们添加的readResolve 方法。 ?...此方法,是通过反射调用 readResolve方法,得到了 rep 对象。 ? ? 然后,判断 rep 是否和 obj 相等 。...obj 是刚才我们通过构造函数创建出来的新对象,而由于我们重写了 readResolve 方法,直接返回了单例对象,因此 rep 就是原来的单例对象,和 obj 不相等。...一句话总结就是:当从对象流 ObjectInputStream 中读取对象时,会检查对象的类否定义了 readResolve 方法。
为了保证单例性,你必须将所有的实例变量声明为transient并提供一个readResolve方法(Item 77)。...为了防止这种情况发生,要在Elvis类中添加readResolve方法: // readResolve method to preserve singleton property private...Object readResolve() { // Return the one true Elvis and let the garbage collector //
object start"); in.defaultReadObject(); //int i=in.readInt(); } private Object readResolve...如果检查失败.则抛出一个InvalidObjectException异常 反序列化验证使用ObjectInputValidation接口 不要调用类中任何可被覆盖的方法 77.对于实例控制,枚举类优先于readResolve...反序列化时, 会调用PersonProxy的readResolve()方法生成一个Person对象, * 最后返回此对象的拷贝 (通过PersonProxy类的readResolve方法和...= original.getHobby(); this.age = original.getAge(); } private Object readResolve...() { System.out.println("PersonProxy.readResolve()"); Person person = new Person
现在我们在 Singleton 类中实现一个 readResolve 方法,该方法直接返回了这个单例对象: 重新执行下,发现结果为 true!...具体是什么原理,我们来看看刚才的 readOrdinaryObject 方法: 可以看到,在条件判断中 desc.hasReadResolveMethod() 会判断类是否有 readResolve(...所以,如果想要防止单例被反序列化破坏,就让单例类实现 readResolve() 方法 反射破坏单例 上面说到,反序列化底层其实就是通过反射来创建一个新对象的,我们直接来看反射是怎么破坏单例的:...总结下,如果今后需要自己手动实现一个单例的话,可以选择【构造函数判断】+【实现 readResolve() 方法】的方式 来防止单例被破坏 优雅的单例实现:Enum 那如果我不想在构造函数里面做判断,也不想写...readResolve() 方法,我就想安安静静写个单例,有没有更简单更优雅的方法?
领取专属 10元无门槛券
手把手带您无忧上云