面試題 -關於Integer(-128~127範圍內)的交換

ー:題目如下

public class IntegerSwapTest {
    public static void main(String[] args) {
        Integer a = 1;
        Integer b = 2;
        System.out.println("before swap: a=" + a + ",b=" + b);
        
        swap(a,b);
        System.out.println("after swap: a=" + a + ",b=" + b);
    }
    // TODO 交換兩個integer的值
    private static void swap(Integer integer1, Integer integer2) {
        
    }
}

二:我們剛開始想到的肯定是依賴第三方變量,因爲integer是包裝類(原以爲他傳遞的是引用)
// TODO 交換兩個integer的值
private static void swap(Integer integer1, Integer integer2) {
    Integer temp = integer1;
    integer1 = integer2;
    integer2 = temp;
}
結果爲:媽耶沒變這怎麼搞
before swap: a=1,b=2
after swap: a=1,b=2


三:java中兩種傳值模式:    ①引用傳遞    ②值傳遞    不過這兩種傳遞的都是副本

integer類是final不允許有子類,且在創建對象的時候要不新建要不就在緩存中拿,並且value的字段是私有也沒有提供getter方法

可以使用javap來查看到底調用的class中的哪種方法
public class Test{
    public static void main(String[] args){
        Integer a = 1;
        int b = a;
    }
}

PS C:\Users\xxx\Desktop> javap -c Test
Compiled from "Test.java"
public class Test {
  public Test();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1
       1: invokestatic  #2                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
       4: astore_1
       5: aload_1
       6: invokevirtual #3                  // Method java/lang/Integer.intValue:()I
       9: istore_2
      10: return
}

可知自動裝箱調用的是valueOf方法,而自動拆箱調用的是intValue方法(該方法類似於get方法)
public int intValue() {
    return value;
}

四:於是我們使用反射來解決這個問題
// TODO 交換兩個integer的值
private static void swap(Integer integer1, Integer integer2) {
    try {
         Field valueField = Integer.class.getDeclaredField("value");
         valueField.setAccessible(true);
         int temp = integer1.intValue();
         valueField.set(integer1, integer2);
         valueField.set(integer2, temp);
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
}
before swap: a=1,b=2
after swap: a=2,b=2

因爲對象都是公用的一份字節碼文件,value變爲可變的之後,即內存中Integer對象會都變爲value可變,包括在IntegerCache.cache[]中的緩存都會改變
於是
0.int temp = 1;
1.integer1中的value變爲2(IntegerCache.cache[131]),即IntegerCache.cache[130]變爲2;
2.integer2中的value調用set的時候,會先把1轉爲Integer(IntegerCache.cache[130])的再取得他的intValue()值,則還是2;


UnsafeQualifiedIntegerFieldAccessorImpl.class

五:解決方法
〇:只要不在緩存池裏就不存在這個問題
①:再新new一個1的Integer
int temp = integer1.intValue();
valueField.set(integer1, integer2);
valueField.set(integer2, new Integer(temp));
②:使用指定的方法setInt()
int temp = integer1.intValue();
valueField.set(integer1, integer2);
valueField.setInt(integer2, temp);
③:從一位大哥那裏學到的(最終解法) 
// TODO 交換兩個integer的值
private static void swap(Integer integer1, Integer integer2) {
    System.out.println("after swap: a=2,b=1");
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章