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

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

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java交换两个Integer-一道无聊的题的思考

發(fā)布時(shí)間:2025/4/5 java 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java交换两个Integer-一道无聊的题的思考 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

為什么80%的碼農(nóng)都做不了架構(gòu)師?>>> ??

1.最近網(wǎng)上看到的一道題,有人說(shuō)一道很無(wú)聊的題,但我覺(jué)得有必要記錄一下。

2.題目

?

public static void main(String[] args) throws Exception {Integer a = 3;Integer b = 5;System.out.println("before swap: a="+ a + ",b=" + b);swap(a,b);System.out.println("after swap: a="+ a + ",b=" + b);}public static void swap(Integer a,Integer b) throws Exception {//TODO 請(qǐng)實(shí)現(xiàn)邏輯}

? 看了題目之后,首先想到的是 加減法,異或操作交換等。但仔細(xì)思考之后,發(fā)現(xiàn)考察點(diǎn)并不是這個(gè)。至少,你先要了解java的引用和值傳遞的知識(shí)。

3. Java中都是值傳遞

也就是說(shuō),函數(shù)的參數(shù)變量都是對(duì)原來(lái)值的copy,這也是java和c的一個(gè)明顯區(qū)別。舉個(gè)例子。

1處和2處兩個(gè)引用的指向都是同一塊內(nèi)存,但是count == countCopy答案是false。

你在家看電視,用遙控器正在更換頻道,這時(shí)候你爸跟你說(shuō)“把遙控器給我!剛才那個(gè)節(jié)目很好看”。此時(shí),你為了不丟失對(duì)電視的控制權(quán),你從抽屜里拿了一個(gè)新的遙控器給了你爸(復(fù)制一個(gè)新的)。新、舊兩個(gè)遙控器就如同上面的count,countCopy。

public static void main(String[] args) throws Exception {Integer count = new Integer(100);//1test(count);}public static void test(Integer countCopy){//2System.out.println(countCopy);}

?

4.回到題目

如果給出的不是引用類(lèi)型Integer而是int交換,這題是無(wú)解的。因?yàn)閟wap函數(shù)里的a,b都是引用的copy。所以你改變swap中a,b的引用指向是沒(méi)用的,因?yàn)闊o(wú)法影響到主函數(shù)中的引用a,b的指向。所以思路還是只能從更改引用指向的真實(shí)內(nèi)存值來(lái)解決(要拆開(kāi)電視,更換零件;只拿著遙控器一噸操作是沒(méi)法讓電視機(jī)硬件產(chǎn)生變化的),所以自然要用到反射了。最初的我解答如下(下面這份代碼是有問(wèn)題的)

public static void swap(Integer a,Integer b) throws Exception {Field valueField = Integer.class.getDeclaredField("value");valueField.setAccessible(true);int tmpA = a.intValue();//3int tmpB = b.intValue();//5valueField.set(a,tmpB);valueField.set(b,tmpA);} //程序輸出結(jié)果before swap: a=3,b=5 3========>5 5========>5 after swap: a=5,b=5

發(fā)生了什么?為什么交換后b=5而不是3?別急我們根據(jù)上面的代碼,進(jìn)行DEBUG。

這里要補(bǔ)充一個(gè)細(xì)節(jié),你可以在valueOf函數(shù)里面打個(gè)斷點(diǎn),發(fā)現(xiàn)的確會(huì)進(jìn)去。

Integer a = 3; //等價(jià)與 Integer a = Integer.valueOf(3);

那么上面有問(wèn)題的代碼??valueField.set(b,tmpA); 因?yàn)閠mpA是int類(lèi)型,在賦值的時(shí)候也會(huì)隱式調(diào)用Integer.valueOf封裝成對(duì)象,然后再進(jìn)行set賦值。懷疑問(wèn)題就是在set這個(gè)方法了嗎?但是 valueField.set(a,tmpB);是有效的,valueField.set(b,tmpA)是無(wú)效的。稍微改動(dòng)一下程序,進(jìn)一步探索。

public static void swap(Integer a,Integer b) throws Exception {Field valueField = Integer.class.getDeclaredField("value");valueField.setAccessible(true);int tmpA = a.intValue();//3int tmpB = b.intValue();//5System.out.println(Integer.valueOf(3)+"======" + Integer.valueOf(5));valueField.set(a,tmpB);System.out.println(Integer.valueOf(3)+"======" + Integer.valueOf(5));valueField.set(b,tmpA);System.out.println(Integer.valueOf(3)+"======" + Integer.valueOf(5)); }

程序輸出

before swap: a=3,b=5 3======5 5======5 5======5 after swap: a=5,b=5

可以發(fā)現(xiàn)在第一個(gè)進(jìn)行反射賦值valueField.set(a,tmpB);后,Integer.valueOf(3) 等于 5 ???

進(jìn)去看看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è)什么鬼?而且IntegerCache.low = -128,?IntegerCache.high?= 127。valueOf(3)肯定會(huì)命中緩存,那么通過(guò)Debug調(diào)試,發(fā)現(xiàn)IntegerCache的確出錯(cuò)了,cache[3] = 5 (其實(shí)真實(shí)3的緩存下標(biāo)并不是3,而是i + (-IntegerCache.low),這里便于說(shuō)明理解)。

經(jīng)過(guò)這些分析,問(wèn)題表現(xiàn)在?valueField.set(a,tmpB); 賦值后?

命中IntegerCache,獲取cache(5)即5,并更新緩存cache(3)=5

那么如果解決呢,其實(shí)只要避開(kāi)調(diào)用valueOf即可,也就是通過(guò)new Integer()來(lái)繞開(kāi)緩存。修改后的代碼如下:

public static void swap(Integer a,Integer b) throws Exception {Field valueField = Integer.class.getDeclaredField("value");valueField.setAccessible(true);int tmpA = a.intValue();//3int tmpB = b.intValue();//5System.out.println(Integer.valueOf(3)+"======" + Integer.valueOf(5));valueField.set(a,new Integer(tmpB));System.out.println(Integer.valueOf(3)+"======" + Integer.valueOf(5));valueField.set(b,new Integer(tmpA));System.out.println(Integer.valueOf(3)+"======" + Integer.valueOf(5)); }//輸出before swap: a=3,b=5 3======5 5======5 5======3 after swap: a=5,b=3

但是 Integer.valueOf(3)的值還是5,如果程序的其他地方也用到了Integer.value(3)那么將造成致命bug。所以說(shuō)盡量不要用反射去改變類(lèi)的私有變量。

?

轉(zhuǎn)載于:https://my.oschina.net/eqshen/blog/3036658

總結(jié)

以上是生活随笔為你收集整理的Java交换两个Integer-一道无聊的题的思考的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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