日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

单例模式存在的问题——破坏单例模式,序列化和反射

發(fā)布時(shí)間:2025/4/16 编程问答 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 单例模式存在的问题——破坏单例模式,序列化和反射 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

破壞單例模式:

使上面定義的單例類(Singleton)可以創(chuàng)建多個(gè)對(duì)象,枚舉方式除外。

有兩種方式,分別是序列化和反射



序列化反序列化

Singleton類:

public class Singleton implements Serializable {//私有構(gòu)造方法private Singleton() {}private static class SingletonHolder {private static final Singleton INSTANCE = new Singleton();}//對(duì)外提供靜態(tài)方法獲取該對(duì)象public static Singleton getInstance() {return SingletonHolder.INSTANCE;} }

Test類:

public class Test {public static void main(String[] args) throws Exception {//往文件中寫(xiě)對(duì)象//writeObject2File();//從文件中讀取對(duì)象Singleton s1 = readObjectFromFile();Singleton s2 = readObjectFromFile();//判斷兩個(gè)反序列化后的對(duì)象是否是同一個(gè)對(duì)象System.out.println(s1 == s2);}private static Singleton readObjectFromFile() throws Exception {//創(chuàng)建對(duì)象輸入流對(duì)象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Think\\Desktop\\a.txt"));//第一個(gè)讀取Singleton對(duì)象Singleton instance = (Singleton) ois.readObject();return instance;}public static void writeObject2File() throws Exception {//獲取Singleton類的對(duì)象Singleton instance = Singleton.getInstance();//創(chuàng)建對(duì)象輸出流ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Think\\Desktop\\a.txt"));//將instance對(duì)象寫(xiě)出到文件中oos.writeObject(instance);} }

上面代碼運(yùn)行結(jié)果是false,表明序列化和反序列化已經(jīng)破壞了單例設(shè)計(jì)模式。



反射

Singleton類:

package com.itheima.pattern.singleton.demo8;public class Singleton {//私有構(gòu)造方法private Singleton() {}private static volatile Singleton instance;//對(duì)外提供靜態(tài)方法獲取該對(duì)象public static Singleton getInstance() {if(instance != null) {return instance;}synchronized (Singleton.class) {if(instance != null) {return instance;}instance = new Singleton();return instance;}} }

Client.java

package com.itheima.pattern.singleton.demo8;import java.lang.reflect.Constructor;/*** @version v1.0* @ClassName: Client* @Description:* 測(cè)試使用反射破壞單例模式* @Author: dym*/ public class Client {public static void main(String[] args) throws Exception {//1,獲取Singleton的字節(jié)碼對(duì)象Class clazz = Singleton.class;//2,獲取無(wú)參構(gòu)造方法對(duì)象Constructor cons = clazz.getDeclaredConstructor();//3,取消訪問(wèn)檢查cons.setAccessible(true);//4,創(chuàng)建Singleton對(duì)象Singleton s1 = (Singleton) cons.newInstance();Singleton s2 = (Singleton) cons.newInstance();System.out.println(s1 == s2); //如果返回的是true,說(shuō)明并沒(méi)有破壞單例模式,如果是false,說(shuō)明破壞了單例模式} }

上面代碼運(yùn)行結(jié)果是false,表明序列化和反序列化已經(jīng)破壞了單例設(shè)計(jì)模式

注意:枚舉方式不會(huì)出現(xiàn)這兩個(gè)問(wèn)題。



問(wèn)題的解決

  • 序列化、反序列方式破壞單例模式的解決方法

    在Singleton類中添加readResolve()方法,在反序列化時(shí)被反射調(diào)用

? ? ? ? ? ? ? ? ?如果定義了這個(gè)方法,就返回這個(gè)方法的值,如果沒(méi)有定義,則返回新new出來(lái)的對(duì)象。

Singleton類:

package com.itheima.pattern.singleton.demo7;import java.io.Serializable;/*** @version v1.0* @ClassName: Singleton* @Description: 靜態(tài)內(nèi)部類方式* * @Author: dym*/ public class Singleton implements Serializable {//私有構(gòu)造方法private Singleton() {}//定義一個(gè)靜態(tài)內(nèi)部類private static class SingletonHolder {//在內(nèi)部類中聲明并初始化外部類的對(duì)象private static final Singleton INSTANCE = new Singleton();}//提供公共的訪問(wèn)方式public static Singleton getInstance() {return SingletonHolder.INSTANCE;}//當(dāng)進(jìn)行反序列化時(shí),會(huì)自動(dòng)調(diào)用該方法,將該方法的返回值直接返回public Object readResolve() {return SingletonHolder.INSTANCE;}}

Client.java

package com.itheima.pattern.singleton.demo7;import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream;/*** @version v1.0* @ClassName: Client* @Description:* 測(cè)試使用序列化破壞單例模式** 桌面路徑: C:\Users\Think\Desktop* * @Author: dym*/ public class Client {public static void main(String[] args) throws Exception { // writeObject2File();readObjectFromFile();readObjectFromFile();}//從文件讀取數(shù)據(jù)(對(duì)象)public static void readObjectFromFile() throws Exception {//1,創(chuàng)建對(duì)象輸入流對(duì)象ObjectInputStream ois = new ObjectInputStream(new FileInputStream("C:\\Users\\Administrator\\Desktop\\a.txt"));//2,讀取對(duì)象Singleton instance = (Singleton) ois.readObject();System.out.println(instance);//釋放資源ois.close();}//向文件中寫(xiě)數(shù)據(jù)(對(duì)象)public static void writeObject2File() throws Exception {//1,獲取Singleton對(duì)象Singleton instance = Singleton.getInstance();//2,創(chuàng)建對(duì)象輸出流對(duì)象ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("C:\\Users\\Administrator\\Desktop\\a.txt"));//3,寫(xiě)對(duì)象oos.writeObject(instance);//4,釋放資源oos.close();} }



源碼解析:

ObjectInputStream類

public final Object readObject() throws IOException, ClassNotFoundException{...// if nested read, passHandle contains handle of enclosing objectint outerHandle = passHandle;try {Object obj = readObject0(false);//重點(diǎn)查看readObject0方法..... }private Object readObject0(boolean unshared) throws IOException {...try {switch (tc) {...case TC_OBJECT:return checkResolve(readOrdinaryObject(unshared));//重點(diǎn)查看readOrdinaryObject方法...}} finally {depth--;bin.setBlockDataMode(oldMode);} }private Object readOrdinaryObject(boolean unshared) throws IOException {...//isInstantiable 返回true,執(zhí)行 desc.newInstance(),通過(guò)反射創(chuàng)建新的單例類,obj = desc.isInstantiable() ? desc.newInstance() : null; ...// 在Singleton類中添加 readResolve 方法后 desc.hasReadResolveMethod() 方法執(zhí)行結(jié)果為trueif (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()) {// 通過(guò)反射調(diào)用 Singleton 類中的 readResolve 方法,將返回值賦值給rep變量// 這樣多次調(diào)用ObjectInputStream類中的readObject方法,繼而就會(huì)調(diào)用我們定義的readResolve方法,所以返回的是同一個(gè)對(duì)象。Object rep = desc.invokeReadResolve(obj);...}return obj; }

反射方式破解單例的解決方法

public class Singleton {//私有構(gòu)造方法private Singleton() {/*反射破解單例模式需要添加的代碼*/if(instance != null) {throw new RuntimeException();}}private static volatile Singleton instance;//對(duì)外提供靜態(tài)方法獲取該對(duì)象public static Singleton getInstance() {if(instance != null) {return instance;}synchronized (Singleton.class) {if(instance != null) {return instance;}instance = new Singleton();return instance;}} }

或者是這種方式

package com.itheima.pattern.singleton.demo8;/*** @version v1.0* @ClassName: Singleton* @Description: 靜態(tài)內(nèi)部類方式* * @Author: dym*/ public class Singleton {private static boolean flag = false;//私有構(gòu)造方法private Singleton() {synchronized (Singleton.class) {//判斷flag的值是否是true,如果是true,說(shuō)明非第一次訪問(wèn),直接拋一個(gè)異常,如果是false的話,說(shuō)明第一次訪問(wèn)if (flag) {throw new RuntimeException("不能創(chuàng)建多個(gè)對(duì)象");}//將flag的值設(shè)置為trueflag = true;}}//定義一個(gè)靜態(tài)內(nèi)部類private static class SingletonHolder {//在內(nèi)部類中聲明并初始化外部類的對(duì)象private static final Singleton INSTANCE = new Singleton();}//提供公共的訪問(wèn)方式public static Singleton getInstance() {return SingletonHolder.INSTANCE;} }

Client.java

package com.itheima.pattern.singleton.demo8;import java.lang.reflect.Constructor;/*** @version v1.0* @ClassName: Client* @Description:* 測(cè)試使用反射破壞單例模式* * @Author: dym*/ public class Client {public static void main(String[] args) throws Exception {//1,獲取Singleton的字節(jié)碼對(duì)象Class clazz = Singleton.class;//2,獲取無(wú)參構(gòu)造方法對(duì)象Constructor cons = clazz.getDeclaredConstructor();//3,取消訪問(wèn)檢查cons.setAccessible(true);//4,創(chuàng)建Singleton對(duì)象Singleton s1 = (Singleton) cons.newInstance();Singleton s2 = (Singleton) cons.newInstance();System.out.println(s1 == s2); //如果返回的是true,說(shuō)明并沒(méi)有破壞單例模式,如果是false,說(shuō)明破壞了單例模式} }

總結(jié)

以上是生活随笔為你收集整理的单例模式存在的问题——破坏单例模式,序列化和反射的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。