最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

詳解Java序列化如何破壞單例模式

 更新時間:2023年12月15日 08:15:55   作者:大明哥_  
這篇文章主要為大家詳細(xì)介紹了Java序列化是如何破壞單例模式的,文中的示例代碼講解詳細(xì),具有一定的借鑒價值,感興趣的小伙伴可以學(xué)習(xí)一下

先看代碼:

public class Singleton {
    private Singleton(){}

    private static class SingletonInstance{
        private static final Singleton instance = new Singleton();
    }

    public static Singleton getInstance(){
        return SingletonInstance.instance;
    }
}

我想應(yīng)該沒有不知道這行個類是干嘛的小伙伴了吧,這是單例模式的一種寫法。

單例模式是每一個 Java boy 必須要掌握的設(shè)計模式,它所描述的是在某個進(jìn)程內(nèi),某個類有且僅有一個實例。我們知道要破壞單例模式就必須讓它創(chuàng)建多個對象。創(chuàng)建對象的方式無非就幾種:

  • new
  • clone
  • 反射
  • 反序列化

首先單例模式的構(gòu)造器一定是 private 的,所以 new 這種方式是無法破壞單例模式的。 而 clone 需要實現(xiàn) Cloneable 接口,單例模式誰如果實現(xiàn)了這個接口,請打死它。所以就剩下反射和反序列化了。本篇文章只討論反序列化。

反序列化破壞單例模式

與 clone 方式一樣,反序列化需要實現(xiàn) Serializable 接口,但是有小伙伴可能會說,誰會在單例模式中實現(xiàn) Serializable 接口咯,除非他瘋了,確實是這種情況,但是在實際情況中它并不是一定會避免的,有些類它就是一定要序列化。比如單例對象在不同環(huán)境或應(yīng)用實例之間的共享、持久化或狀態(tài)恢復(fù),當(dāng)然這些場景都屬于比較特殊的場景。

繼續(xù)用上面例子:

public class SerializableSingleton implements Serializable {
    // 省略部分代碼
}

然后在對該類進(jìn)行序列化和反序列化

public class Test {
    public static void main(String[] args) throws Exception {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Singleton.txt"));
        SerializableSingleton singleton = SerializableSingleton.getInstance();
        oos.writeObject(singleton);

        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Singleton.txt"));
        SerializableSingleton singleton1 = (SerializableSingleton) ois.readObject();

        System.out.println("singleton = singleton1:" + (singleton == singleton1));
    }
}

運(yùn)行結(jié)果

singleton = singleton1:false

通過對 Singleton 進(jìn)行反序列化得到了一個全新的對象,這就破壞了 Singleton 的單例性了。我們看 readObject() 源碼就知道了。

    public final Object readObject() throws IOException, ClassNotFoundException {
        //...
        int outerHandle = passHandle;
        try {
            Object obj = readObject0(false);
            //...
            return obj;
        } finally {
            //...
        }
    }

調(diào)用 readObject0()

    private Object readObject0(boolean unshared) throws IOException {
        // ...
        try {
            switch (tc) {
                // ...

                case TC_OBJECT:
                    // readObject0()
                    return checkResolve(readOrdinaryObject(unshared));
                // ...
            }
        } finally {
            depth--;
            bin.setBlockDataMode(oldMode);
        }
    }

readObject0() 是根據(jù)反序列化對象的不同執(zhí)行不同的方法來反序列化一個實例對象。我們這里是 Object,所以進(jìn)一步看 readOrdinaryObject()。

    private Object readOrdinaryObject(boolean unshared) throws IOException {
        // ...

        Object obj;
        try {
            // 核心代碼
            // 反射創(chuàng)建一個新對象
            obj = desc.isInstantiable() ? desc.newInstance() : null;
        } catch (Exception ex) {
            throw (IOException) new InvalidClassException(
                desc.forClass().getName(),
                "unable to create instance").initCause(ex);
        }
        
        // ...

        if (obj != null &&
            handles.lookupException(passHandle) == null &&
            desc.hasReadResolveMethod()) {
            Object rep = desc.invokeReadResolve(obj);
            if (unshared && rep.getClass().isArray()) {
                rep = cloneArray(rep);
            }
            if (rep != obj) {
                // Filter the replacement object
                if (rep != null) {
                    if (rep.getClass().isArray()) {
                        filterCheck(rep.getClass(), Array.getLength(rep));
                    } else {
                        filterCheck(rep.getClass(), -1);
                    }
                }
                handles.setObject(passHandle, obj = rep);
            }
        }

        return obj;
    }

這段代碼最核心的地方就是:

obj = desc.isInstantiable() ? desc.newInstance() : null;

底層依然是利用反射的方式來創(chuàng)建一個新對象。

那么對于這種方式有什么保護(hù)措施沒?在 readOrdinaryObject() 最后面一段就已經(jīng)告知了:

if (obj != null && handles.lookupException(passHandle) == null &&
      desc.hasReadResolveMethod()) {
     //....
 }        

判斷反序列化的類是否已實現(xiàn)了 readResolve() ,如果有則會調(diào)用該方法,我們只需要在該方法里面返回原對象就可以了。驗證下。

public class SerializableSingleton implements Serializable {
    // ...
    private Object readResolve() {
        return SingletonInstance.instance;
    }
}

執(zhí)行結(jié)果:

singleton = singleton1:true

執(zhí)行結(jié)果為 true,就說明序列化和反序列化出來的是同一個對象。

所以,要想防止單例被反序列化破壞,就讓單例實現(xiàn) readResolve()方法,返回同一個對象即可。

到此這篇關(guān)于詳解Java序列化如何破壞單例模式的文章就介紹到這了,更多相關(guān)Java序列化內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java8 streamList轉(zhuǎn)換使用詳解

    java8 streamList轉(zhuǎn)換使用詳解

    這篇文章主要介紹了java8 streamList轉(zhuǎn)換使用詳解,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-08-08
  • spring?webflux響應(yīng)式編程使用詳解

    spring?webflux響應(yīng)式編程使用詳解

    webflux,即響應(yīng)式編程,響應(yīng)式編程是一種用于處理異步數(shù)據(jù)流和事件的編程范式,spring?webflux是spring在5.0版本后提供的一套響應(yīng)式編程風(fēng)格的web開發(fā)框架,本文給大家詳細(xì)講講spring?webflux響應(yīng)式編程的使用,需要的朋友可以參考下
    2023-10-10
  • cmd中javac和java使用及注意事項詳解

    cmd中javac和java使用及注意事項詳解

    這篇文章主要介紹了cmd中javac和java使用及注意事項詳解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2019-07-07
  • Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法

    Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法

    這篇文章主要介紹了Eclipse 出現(xiàn)Failed to load JavaHL Library解決方法的相關(guān)資料,今天使用Eclipse 時出現(xiàn)以上錯誤,本文說明如何更更正,需要的朋友可以參考下
    2016-11-11
  • Java獲取代碼中方法參數(shù)名信息的方法

    Java獲取代碼中方法參數(shù)名信息的方法

    在java中,可以通過反射獲取到類、字段、方法簽名等相關(guān)的信息,像方法名、返回值類型、參數(shù)類型、泛型類型參數(shù)等,但是不能夠獲取方法的參數(shù)名。在實際開發(fā)場景中,有時需要根據(jù)方法的參數(shù)名做一些操作,那么該如何操作了呢?下面就通過這篇文章來學(xué)習(xí)學(xué)習(xí)吧。
    2016-09-09
  • Java時間處理第三方包Joda?Time使用詳解

    Java時間處理第三方包Joda?Time使用詳解

    這篇文章主要為大家介紹了Java時間處理第三方包Joda?Time使用詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-07-07
  • @Accessors(chain = true)注解報錯的解決方案

    @Accessors(chain = true)注解報錯的解決方案

    這篇文章主要介紹了@Accessors(chain = true)注解報錯的解決方案,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • httpclient evict操作源碼解讀

    httpclient evict操作源碼解讀

    這篇文章主要為大家介紹了httpclient evict操作源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-10-10
  • Spring Mybatis 基本使用過程(推薦)

    Spring Mybatis 基本使用過程(推薦)

    Mybatis是一個半自動ORM(Object Relational Mapping)框架,它可以簡化數(shù)據(jù)庫編程,讓開發(fā)者更專注于SQL本身,本文給大家介紹Spring Mybatis 基本使用過程,感興趣的朋友跟隨小編一起看看吧
    2024-09-09
  • Spring Boot Admin實現(xiàn)服務(wù)健康預(yù)警功能

    Spring Boot Admin實現(xiàn)服務(wù)健康預(yù)警功能

    這篇文章主要介紹了Spring Boot Admin實現(xiàn)服務(wù)健康預(yù)警功能,本文通過實例代碼給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-05-05

最新評論

普安县| 文水县| 罗平县| 日土县| 商水县| 台中县| 二连浩特市| 榆树市| 济源市| 霍邱县| 崇仁县| 黄大仙区| 浮山县| 龙门县| 射洪县| 九台市| 自治县| 钟祥市| 福海县| 无为县| 澄迈县| 兴宁市| 南丰县| 北流市| 宁化县| 鹤岗市| 尚义县| 平塘县| 河池市| 黄陵县| 新闻| 罗甸县| 曲阳县| 平乡县| 渑池县| 秦安县| 台北县| 自贡市| 岫岩| 库伦旗| 松阳县|