1. 程式人生 > >反射交換兩個值的大小引發的思考

反射交換兩個值的大小引發的思考

發現問題:

最近在學習java的時候在java群裡面看到一個問題,就是用反射來實現兩個值的交換,然後結果沒有按群友的預期去執行.群裡的程式碼如下:
原程式
群友想的結果是a=1,b=2;a=2,b=1;
然而結果是
這裡寫圖片描述
然後就覺得很奇怪,交換完以後,a,b都變成了2.

問題探究過程

(和群友一起討論出來的,一開始自己也覺得很奇怪,涉及到java的自動裝箱和Integer類的原始碼設計問題):
1.首先將原始碼反編譯,推薦使用jad下載地址,eclipse和idea上也有相應的外掛.反編譯出來如下:
這裡寫圖片描述
可以看到Integer a = 1;這種類似的地方進行了自動裝箱;int tmp = num1,進行了自動拆箱.分別使用的是valueOf(),intValue();
2.然後我們去檢視Integer的原始碼發現,如下圖:
這裡寫圖片描述


這裡寫圖片描述
這裡寫圖片描述
    (1).Integer類裡面有個叫IntegerCache的Integer型別的快取陣列;
    (2).cache裡面的值從圖中可以看出是從-128到127,一共256個整型數值;
    (3).我們使用的Integer的值來源於final型別的value,正常情況是不可變的,但是用了反射,設定了field.setAccessible(true);就可以改變value的值,群友也正是想用反射來改變value的值,從而達到交換數值的目的.
3.在自動裝箱valueOf()打了斷點,在進行第二次的交換field.set(num2, tmp)的時候如圖:
這裡寫圖片描述

發現cache的129位置原來應該是1的值,變成了2.所以記憶體中的Integer的cache[129]的值都變成了2,因此結果b=2,tmp=2.

結果分析:

1.field.set(num1, num2)的時候,反射將原本value=1的IntegerCache中的cache[129]的值修改為了2.所以在field.set(num2, tmp)的時候,是將num2(cache[129]等於2)的值賦值給了tmp(也變為2).
2.因為快取陣列的大小是在-128-127之間,所以我們將a,b的值都大於127的時候用反射來交換數值的大小是不會出問題的,因為不在快取陣列中的數值,會重新生成.如圖:
這裡寫圖片描述


結果:
這裡寫圖片描述
這樣交換是沒有問題的.

自我總結:

一.是反射不要亂用,可能會有你想不到的後果;
二是涉及到自動裝箱的可能會有坑,最好使用Integer i = new Integer(‘數字’);這樣就不會有Cache陣列的坑,因為是重新新建了一個Integer的物件.