java 方法中交換Integer類型的局部變量a,b

??自己的第一篇博客,各位看官多多指教母赵。這里講的是一道面試題逸爵,題目如下:

    //要求寫一個(gè)swap方法交換ab值輸出打印a=2 b=1
    public static void main(String[] args) {
        Integer a=1,b=2;
        swap(a,b);
        System.out.println("a="+a+"   b="+b);
    }

??這道題目所涉及到的知識(shí)點(diǎn)包括:

  • Integer的自動(dòng)裝箱
  • java的值傳遞和引用傳遞
  • 對(duì)Integer類的源碼分析
  • java的反射機(jī)制
1. Integer的自動(dòng)裝箱

??java的自動(dòng)裝箱就是自動(dòng)將原始數(shù)據(jù)類型(byte,short,char,int,long,float,double,boolean)轉(zhuǎn)換成對(duì)應(yīng)的基本數(shù)據(jù)類型包裝類對(duì)象(Byte,Short,Character,Integer,Long,Float,Double,Boolean)具滴,比如將int的變量轉(zhuǎn)換成Integer對(duì)象
這里的Integer a=1 經(jīng)過自動(dòng)裝箱以后變?yōu)?br> Integer a=Integer.valueOf(1);
那么我們接著查看Integer類中的valueOf()方法如下:

    public static Integer valueOf(int i) {
        if (i >= IntegerCache.low && i <= IntegerCache.high)
            return IntegerCache.cache[i + (-IntegerCache.low)];
        return new Integer(i);
    }

??接著查看IntegerCache這個(gè)內(nèi)部類可以發(fā)現(xiàn)java虛擬機(jī)在我們首次使用Integer的時(shí)候會(huì)初始化數(shù)值在-128-127之間的整數(shù)凹嘲,而且這個(gè)區(qū)間范圍可以在虛擬機(jī)啟動(dòng)的時(shí)候自己設(shè)定。換句話說构韵,數(shù)值在-128-127之間的相同整數(shù)都會(huì)取自相同的內(nèi)存具體值周蹭。下面例子中a和b都是指向相同的內(nèi)存地址,而x和y指向兩塊不同的內(nèi)存地址疲恢。

    Integer x=-129;
    Integer y=-129;
    System.out.println(x==y);    //輸出false
    Integer a=-128;
    Integer b=-128;
    System.out.println(a==b);    //輸出true
    Integer xx=new Integer(1);
    Integer yy=new Integer(1);
    System.out.println(xx==yy);    //輸出false

??說到這里必須說一下valueOf(int i)方法最終返回的是new Integer(i);而Integer類的構(gòu)造函數(shù)如下凶朗,這里的value是解題的關(guān)鍵,value在Integer類中是一個(gè)final的私有成員變量显拳。

    public Integer(int value) {
        this.value = value;
    }

說出正確答案之前還得看看Integer的源碼中的toString方法
public String toString() { return toString(value); }
可見其返回的真實(shí)值就是value棚愤,并且value就是在構(gòu)造函數(shù)中初始化的。在swap方法中我們拿到了Integer的引用杂数,那么我們就可以通過反射來改變對(duì)應(yīng)實(shí)例的局部變量值宛畦。具體代碼如下:

    private static void swap1(Integer aa, Integer bb) {
        try {
            Field aaValue = aa.getClass().getDeclaredField("value");
            aaValue.setAccessible(true);
            aaValue.set(aa,2);
            Field bbValue = bb.getClass().getDeclaredField("value");
            bbValue.setAccessible(true);
            bbValue.set(bb,1);
            System.out.println(Integer.valueOf(1));//輸出2
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

但是運(yùn)行之后我們發(fā)現(xiàn)其結(jié)果是:

a=2   b=2

??看到這里是不是感覺很不可思議,但是我們距離真相已經(jīng)很近了揍移。我們疑惑的是為什么b的值沒有發(fā)生改變次和,更疑惑的是為什么Integer.valueOf(1)輸出的竟然是2。這是因?yàn)榛緮?shù)據(jù)類型在-128-127之間的數(shù)都會(huì)自動(dòng)裝箱并且從緩存中去取那伐,我們反射改變的只是緩存中的1對(duì)應(yīng)的實(shí)例的實(shí)例變量value值踏施,我們?cè)赽bValue.set(bb,1);的時(shí)候1會(huì)自動(dòng)裝箱去緩存中去找,而這時(shí)緩存中的Integer.valueOf(1)已經(jīng)是2罕邀,所以返回的還是2畅形。解決的方法就是不讓其去緩存中找,參考代碼如下:

    //正解
    private static void swap1(Integer aa, Integer bb) {
        try {
            Field aaValue = aa.getClass().getDeclaredField("value");
            aaValue.setAccessible(true);
            aaValue.set(aa,2);
            Field bbValue = bb.getClass().getDeclaredField("value");
            bbValue.setAccessible(true);
            //這里的1不會(huì)自動(dòng)裝箱诉探,當(dāng)然就不會(huì)從緩存中去取值
            bbValue.set(bb,new Integer(1));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

??這里還是要多說一句日熬,如果a,b變量的值是-128-127之外的整數(shù)的話雖然會(huì)自動(dòng)裝箱阵具,但是不會(huì)從緩存中去取值碍遍,那么bbValue.set(bb,-128-127之外的整數(shù));就可以了,是不用專門new Integer()的阳液,參考代碼如下:

    public static void main(String[] args) {
        Integer a=999;
        Integer b=888;
        swap1(a,b);
        System.out.println("a="+a+"   b="+b);
    }
    private static void swap1(Integer aa, Integer bb) {
        try {
            Field aaValue = aa.getClass().getDeclaredField("value");
            aaValue.setAccessible(true);
            aaValue.set(aa,888);
            Field bbValue = bb.getClass().getDeclaredField("value");
            bbValue.setAccessible(true);
            bbValue.set(bb,999);//這里沒有new Integer(999)
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

輸出結(jié)果為a=888 b=999

2. 錯(cuò)誤答案示例

??對(duì)于這道題目的解法有些同學(xué)可能會(huì)給出下面的答案怕敬,明顯是錯(cuò)誤的,因?yàn)樗鼈兙唧w交換的還是aa和bb所指向的內(nèi)存地址值帘皿,而這一塊內(nèi)存地址值所指向的內(nèi)存空間的內(nèi)容并沒有改變东跪,所以a和b變量是沒有變化的(參考圖1)。

    private static void swap(Integer aa,Integer bb){
        Integer temp;
        temp=aa;
        bb=temp;
        aa=bb;
    }

??按照我自己的理解,java的值傳遞和引用傳遞實(shí)際上都是值傳遞虽填,因?yàn)橐脗鬟f最終傳遞的還是引用對(duì)象的內(nèi)存具體值(下圖紅色線條代表交換后的狀態(tài)丁恭,可見a和b并沒有發(fā)生變化)


圖1.引用傳遞(紅線代表交換后)
3. 題目變種
    //對(duì)于這道題是不能用反射的,因?yàn)槭腔緮?shù)據(jù)類型的值傳遞
    public static void main(String[] args) {
        int a=1;
        int b=2;
        swap(a,b);
        System.out.println("a="+a+"   b="+b);
    }

投機(jī)取巧的做法如下:

    public static void main(String[] args) {
        int a=1;
        int b=2;
        swap(a,b);
        System.out.println("a="+a+"   b="+b);
    }
    private static void swap(Integer aa, Integer bb) {
        System.out.println("a="+2+"   b="+1);
        System.exit(0);
    }

??題目雖小斋日,卻包含很多知識(shí)點(diǎn)牲览,希望大家能夠有所收獲,歡迎留言討論恶守!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末第献,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兔港,更是在濱河造成了極大的恐慌庸毫,老刑警劉巖,帶你破解...
    沈念sama閱讀 211,123評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件衫樊,死亡現(xiàn)場離奇詭異飒赃,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)科侈,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,031評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門载佳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人兑徘,你說我怎么就攤上這事刚盈。” “怎么了挂脑?”我有些...
    開封第一講書人閱讀 156,723評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵藕漱,是天一觀的道長。 經(jīng)常有香客問我崭闲,道長肋联,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 56,357評(píng)論 1 283
  • 正文 為了忘掉前任刁俭,我火速辦了婚禮橄仍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘牍戚。我一直安慰自己侮繁,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,412評(píng)論 5 384
  • 文/花漫 我一把揭開白布如孝。 她就那樣靜靜地躺著宪哩,像睡著了一般。 火紅的嫁衣襯著肌膚如雪第晰。 梳的紋絲不亂的頭發(fā)上锁孟,一...
    開封第一講書人閱讀 49,760評(píng)論 1 289
  • 那天彬祖,我揣著相機(jī)與錄音,去河邊找鬼品抽。 笑死储笑,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的圆恤。 我是一名探鬼主播突倍,決...
    沈念sama閱讀 38,904評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼哑了!你這毒婦竟也來了赘方?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,672評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤弱左,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后炕淮,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體拆火,經(jīng)...
    沈念sama閱讀 44,118評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,456評(píng)論 2 325
  • 正文 我和宋清朗相戀三年涂圆,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了们镜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,599評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡润歉,死狀恐怖模狭,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情踩衩,我是刑警寧澤嚼鹉,帶...
    沈念sama閱讀 34,264評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站驱富,受9級(jí)特大地震影響锚赤,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜褐鸥,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,857評(píng)論 3 312
  • 文/蒙蒙 一线脚、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧叫榕,春花似錦浑侥、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,731評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至寒匙,卻和暖如春零如,著一層夾襖步出監(jiān)牢的瞬間躏将,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,956評(píng)論 1 264
  • 我被黑心中介騙來泰國打工考蕾, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留祸憋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,286評(píng)論 2 360
  • 正文 我出身青樓肖卧,卻偏偏與公主長得像蚯窥,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子塞帐,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,465評(píng)論 2 348

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理拦赠,服務(wù)發(fā)現(xiàn),斷路器葵姥,智...
    卡卡羅2017閱讀 134,628評(píng)論 18 139
  • Java8張圖 11荷鼠、字符串不變性 12、equals()方法榔幸、hashCode()方法的區(qū)別 13允乐、...
    Miley_MOJIE閱讀 3,696評(píng)論 0 11
  • 自動(dòng)裝箱和拆箱從Java1.5開始引入,目的是將原始類型值轉(zhuǎn)自動(dòng)地轉(zhuǎn)換成對(duì)應(yīng)的對(duì)象削咆。自動(dòng)裝箱與拆箱的機(jī)制可以讓我們...
    GB_speak閱讀 619評(píng)論 0 4
  • 下面的內(nèi)容是對(duì)網(wǎng)上原有的Java面試題集及答案進(jìn)行了全面修訂之后給出的負(fù)責(zé)任的題目和答案牍疏,原來的題目中有很多重復(fù)題...
    獨(dú)念白閱讀 1,330評(píng)論 0 3
  • 十六歲的是什么樣的年齡呢,最近不小心點(diǎn)了《最好的我們》看來一點(diǎn)點(diǎn)就不能控制自己的情緒了拨齐。原來十六歲的那年鳞陨,我...
    Mrs簡閱讀 107評(píng)論 0 0