日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

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

發布時間:2025/4/5 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java交换两个Integer-一道无聊的题的思考 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

為什么80%的碼農都做不了架構師?>>> ??

1.最近網上看到的一道題,有人說一道很無聊的題,但我覺得有必要記錄一下。

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 請實現邏輯}

? 看了題目之后,首先想到的是 加減法,異或操作交換等。但仔細思考之后,發現考察點并不是這個。至少,你先要了解java的引用和值傳遞的知識。

3. Java中都是值傳遞

也就是說,函數的參數變量都是對原來值的copy,這也是java和c的一個明顯區別。舉個例子。

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

你在家看電視,用遙控器正在更換頻道,這時候你爸跟你說“把遙控器給我!剛才那個節目很好看”。此時,你為了不丟失對電視的控制權,你從抽屜里拿了一個新的遙控器給了你爸(復制一個新的)。新、舊兩個遙控器就如同上面的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.回到題目

如果給出的不是引用類型Integer而是int交換,這題是無解的。因為swap函數里的a,b都是引用的copy。所以你改變swap中a,b的引用指向是沒用的,因為無法影響到主函數中的引用a,b的指向。所以思路還是只能從更改引用指向的真實內存值來解決(要拆開電視,更換零件;只拿著遙控器一噸操作是沒法讓電視機硬件產生變化的),所以自然要用到反射了。最初的我解答如下(下面這份代碼是有問題的)

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);} //程序輸出結果before swap: a=3,b=5 3========>5 5========>5 after swap: a=5,b=5

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

這里要補充一個細節,你可以在valueOf函數里面打個斷點,發現的確會進去。

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

那么上面有問題的代碼??valueField.set(b,tmpA); 因為tmpA是int類型,在賦值的時候也會隱式調用Integer.valueOf封裝成對象,然后再進行set賦值。懷疑問題就是在set這個方法了嗎?但是 valueField.set(a,tmpB);是有效的,valueField.set(b,tmpA)是無效的。稍微改動一下程序,進一步探索。

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

可以發現在第一個進行反射賦值valueField.set(a,tmpB);后,Integer.valueOf(3) 等于 5 ???

進去看看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是個什么鬼?而且IntegerCache.low = -128,?IntegerCache.high?= 127。valueOf(3)肯定會命中緩存,那么通過Debug調試,發現IntegerCache的確出錯了,cache[3] = 5 (其實真實3的緩存下標并不是3,而是i + (-IntegerCache.low),這里便于說明理解)。

經過這些分析,問題表現在?valueField.set(a,tmpB); 賦值后?

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

那么如果解決呢,其實只要避開調用valueOf即可,也就是通過new Integer()來繞開緩存。修改后的代碼如下:

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。所以說盡量不要用反射去改變類的私有變量。

?

轉載于:https://my.oschina.net/eqshen/blog/3036658

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。