避開類本身的構(gòu)造函數(shù)

背景

最近在用XStream线罕,轉(zhuǎn)換XML到Java對(duì)象時(shí),發(fā)現(xiàn)一個(gè)奇怪的現(xiàn)象般哼。Java對(duì)象中吴汪,在構(gòu)造函數(shù)中取的一些默認(rèn)值,及在字段定義時(shí)賦值的初值蒸眠,這些值由于有初值漾橙,在XML里并沒有映射。結(jié)果在XStream反序列化之后楞卡,還是null霜运,只有在XML中出現(xiàn)的值才會(huì)被賦值。

問題提出

一開始我以為是XStream的能力蒋腮,它會(huì)把XML中沒有的字段找出來淘捡,然后設(shè)置成null。為了證明池摧,然后我在set方法上設(shè)置了斷點(diǎn)焦除,但是發(fā)現(xiàn)代碼并沒有進(jìn)去。我又懷疑是直接反射的變量作彤。然后我又在構(gòu)造函數(shù)里及字段的賦初值的地方設(shè)置了斷點(diǎn)膘魄,結(jié)果發(fā)現(xiàn),依然沒有中斷竭讳。
難道创葡,這個(gè)對(duì)象的構(gòu)造,沒有調(diào)用構(gòu)造函數(shù)绢慢?

分析問題

為了搞清楚這個(gè)問題蹈丸,單步一下代碼,從new XStream(new DomDriver());開始。發(fā)現(xiàn)當(dāng)ReflectionProvider reflectionProvider沒有傳入時(shí)逻杖,會(huì)使用JVM::bestReflectionProvider()方法奋岁,然后返回了Sun14ReflectionProvider
繼續(xù)深入,發(fā)現(xiàn)如下代碼:


    private Constructor getMungedConstructor(Class type) throws NoSuchMethodException {
        final WeakReference ref = (WeakReference)constructorCache.get(type);
        Constructor ctor = (Constructor)(ref == null ? null : ref.get());
        if (ctor == null) {
            ctor = reflectionFactory.newConstructorForSerialization(type, Object.class.getDeclaredConstructor(new Class[0]));
            constructorCache.put(type, new WeakReference(ctor));
        }
        return ctor;
    }

    // in ReflectionFactory
    public Constructor newConstructorForSerialization(Class var1, Constructor var2) {
        if(var2.getDeclaringClass() == var1) {
            return var2;
        } else {
            SerializationConstructorAccessorImpl var3 = (new MethodAccessorGenerator()).generateSerializationConstructor(var1, var2.getParameterTypes(), var2.getExceptionTypes(), var2.getModifiers(), var2.getDeclaringClass());
            Constructor var4 = this.newConstructor(var2.getDeclaringClass(), var2.getParameterTypes(), var2.getExceptionTypes(), var2.getModifiers(), langReflectAccess().getConstructorSlot(var2), langReflectAccess().getConstructorSignature(var2), langReflectAccess().getConstructorAnnotations(var2), langReflectAccess().getConstructorParameterAnnotations(var2));
            this.setConstructorAccessor(var4, var3);
            return var4;
        }
    }

解析

  1. 反序列化使用Sun14ReflectionProvider::getMungedConstructor()方法取構(gòu)造函數(shù)荸百。
  2. 在這里reflectionFactory.newConstructorForSerialization(type, Object.class.getDeclaredConstructor(new Class[0]));傳入了目標(biāo)類型闻伶,及Object類型的默認(rèn)構(gòu)造函數(shù)。
  3. 然后在Sun14ReflectionProvider::newConstructorForSerialization()中用Object類型的構(gòu)造函數(shù)够话,產(chǎn)生了目標(biāo)類型的構(gòu)造函數(shù)蓝翰。

在函數(shù)在sun的API中已經(jīng)提供,Sun14ReflectionProvider::newConstructorForSerialization()分析:

  1. (new MethodAccessorGenerator()).generateSerializationConstructor 返回了SerializationConstructorAccessorImpl對(duì)象女嘲,用于Object構(gòu)造函數(shù)可以訪問目標(biāo)類型畜份。
  2. this.newConstructor來新產(chǎn)生Object類型的構(gòu)造函數(shù)。此函數(shù)是新生產(chǎn)出來的欣尼,和在函數(shù)區(qū)已有的構(gòu)造函數(shù)不是同一個(gè)爆雹。
  3. this.setConstructorAccessor(var4, var3);最后把兩者關(guān)聯(lián)。

最后:幾種ReflectionProvider


    public synchronized ReflectionProvider bestReflectionProvider() {
        if (reflectionProvider == null) {
            try {
                if ( canUseSun14ReflectionProvider() ) {
                    String cls = "com.thoughtworks.xstream.converters.reflection.Sun14ReflectionProvider";
                    reflectionProvider = (ReflectionProvider) loadClass(cls).newInstance();
                } else if (canUseHarmonyReflectionProvider()) { // call isHarmony()
                    String cls = "com.thoughtworks.xstream.converters.reflection.HarmonyReflectionProvider";
                    reflectionProvider = (ReflectionProvider) loadClass(cls).newInstance();
                } 
                if (reflectionProvider == null) {
                    reflectionProvider = new PureJavaReflectionProvider();
                }
            } //...
        }
        return reflectionProvider;
    }
    private boolean canUseSun14ReflectionProvider() {
        return (isSun()
            || isApple()
            || isHPUX()
            || isIBM()
            || isBlackdown()
            || isBEAWithUnsafeSupport()
            || isHitachi()
            || isSAP() 
            || isDiablo())
            && is14()
            && loadClass("sun.misc.Unsafe") != null;
    }
    private static boolean isHarmony() {
        return vendor.indexOf("Apache Software Foundation") != -1;
    }
  1. Sun14ReflectionProvider是最優(yōu)的的反序列化器愕鼓。
  2. Sun14ReflectionProvider反序列化器钙态,Sun, Apple, IBM等各大JVM都有實(shí)現(xiàn),并且版本高于JDK1.4菇晃。
  3. Sun14ReflectionProvider反序列化器內(nèi)部使用的用是sun提供的反射API册倒。
  4. Harmony是Apache Harmony項(xiàng)目,一個(gè)開源的JVM虛擬機(jī)磺送。
  5. 使用XStream時(shí)改為new XStream(new PureJavaReflectionProvider(), new DomDriver());驻子,可以解決此問題,使用類的正常構(gòu)造函數(shù)估灿。

結(jié)論

  1. 類在構(gòu)造時(shí)崇呵,可以避開自己的構(gòu)造函數(shù),而合用Object的構(gòu)造函數(shù)甲捏。
  2. 類字段的初始值的賦值,在編譯時(shí)會(huì)編譯到其構(gòu)造函數(shù)中鞭执。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末司顿,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兄纺,更是在濱河造成了極大的恐慌大溜,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,997評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件估脆,死亡現(xiàn)場(chǎng)離奇詭異钦奋,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,603評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門付材,熙熙樓的掌柜王于貴愁眉苦臉地迎上來朦拖,“玉大人,你說我怎么就攤上這事厌衔¤档郏” “怎么了?”我有些...
    開封第一講書人閱讀 163,359評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵富寿,是天一觀的道長(zhǎng)睬隶。 經(jīng)常有香客問我,道長(zhǎng)页徐,這世上最難降的妖魔是什么苏潜? 我笑而不...
    開封第一講書人閱讀 58,309評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮变勇,結(jié)果婚禮上恤左,老公的妹妹穿的比我還像新娘。我一直安慰自己贰锁,他們只是感情好赃梧,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,346評(píng)論 6 390
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著豌熄,像睡著了一般授嘀。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上锣险,一...
    開封第一講書人閱讀 51,258評(píng)論 1 300
  • 那天蹄皱,我揣著相機(jī)與錄音,去河邊找鬼芯肤。 笑死巷折,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的崖咨。 我是一名探鬼主播锻拘,決...
    沈念sama閱讀 40,122評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼击蹲!你這毒婦竟也來了署拟?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 38,970評(píng)論 0 275
  • 序言:老撾萬榮一對(duì)情侶失蹤歌豺,失蹤者是張志新(化名)和其女友劉穎推穷,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體类咧,經(jīng)...
    沈念sama閱讀 45,403評(píng)論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡馒铃,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,596評(píng)論 3 334
  • 正文 我和宋清朗相戀三年蟹腾,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片区宇。...
    茶點(diǎn)故事閱讀 39,769評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡娃殖,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出萧锉,到底是詐尸還是另有隱情珊随,我是刑警寧澤,帶...
    沈念sama閱讀 35,464評(píng)論 5 344
  • 正文 年R本政府宣布柿隙,位于F島的核電站叶洞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏禀崖。R本人自食惡果不足惜衩辟,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,075評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望波附。 院中可真熱鬧艺晴,春花似錦、人聲如沸掸屡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,705評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽仅财。三九已至狈究,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間盏求,已是汗流浹背抖锥。 一陣腳步聲響...
    開封第一講書人閱讀 32,848評(píng)論 1 269
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留碎罚,地道東北人磅废。 一個(gè)月前我還...
    沈念sama閱讀 47,831評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像荆烈,于是被迫代替她去往敵國(guó)和親拯勉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,678評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理憔购,服務(wù)發(fā)現(xiàn)宫峦,斷路器,智...
    卡卡羅2017閱讀 134,654評(píng)論 18 139
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語法倦始,類相關(guān)的語法斗遏,內(nèi)部類的語法山卦,繼承相關(guān)的語法鞋邑,異常的語法诵次,線程的語...
    子非魚_t_閱讀 31,625評(píng)論 18 399
  • 前言 人生苦多,快來 Kotlin 枚碗,快速學(xué)習(xí)Kotlin逾一! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,201評(píng)論 9 118
  • 從三月份找實(shí)習(xí)到現(xiàn)在肮雨,面了一些公司遵堵,掛了不少,但最終還是拿到小米怨规、百度陌宿、阿里、京東波丰、新浪壳坪、CVTE、樂視家的研發(fā)崗...
    時(shí)芥藍(lán)閱讀 42,243評(píng)論 11 349
  • 經(jīng)常掰烟,讀了關(guān)于愛情的文章之后我總會(huì)覺得很孤獨(dú)爽蝴。因?yàn)槭菃紊砭昧耍吹搅饲閭H的甜蜜和單身者的自白我都會(huì)被觸動(dòng)纫骑。我覺得我...
    灑落的陽光閱讀 96評(píng)論 0 1