1. 程式人生 > >交換兩個變數的誤區(java)

交換兩個變數的誤區(java)

在java中引數的傳遞有兩種方式,傳值和引用,實際上引用也是傳的值。當在一個方法中要交換兩個引數對應的值時,可能會有一系列問題。如下:

package com.xx;

import java.lang.reflect.Field;

public class Test01 {
    public static void main(String[] args) {
        Integer a = 1, b = 2;
        swap(a, b);
        System.out.println("a=" + a + "; b=" + b);
    }

    /**
     * 交換變數a和b的值
     * 
     * @param
a * @param b */
private static void swap(Integer a, Integer b) { int tmp = a.intValue(); a = b; b = tmp; } private static void swap1(Integer a, Integer b) { try { Field field = Integer.class.getDeclaredField("value"); field.setAccessible(true
);//(1) int tmp = a.intValue();//(2) field.set(a, b.intValue());//(3) System.out.println("tmp:" + tmp + "; valueOf:" + Integer.valueOf(tmp));//tmp:1; valueOf:2 System.out.println("a:" + a);//a:2 field.set(b, tmp);//(4-1) //field.set(b, new Integer(tmp));//(4-2)
} catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } } }  

在swap(q,b)方法中直接交換後結果是沒有變化,因為此方法中的兩個變數都是區域性變數,方法執行完後變數失效,所有此種方式不行。

例項中的Integer是一個包裝類,而真正儲存值的是“private final int value;”,value是一個私有的變數,如果改變一個私有變數的值,可以使用反射。

(1):使用Field設定私有方法前,必須設定為可執行的

(2):此時tmp值為1,tmp指向的就是value的記憶體地址,即a的實際的值的記憶體地址

(3):set方法設定的是兩個Object物件,先將b.intValue()轉為包裝類(Integer.valueOf(xx))再設定,b的值在快取池中存在。此時a的值為2,即a中value指向的記憶體值也為2,也就是說tmp此時指向的記憶體地址的值為2

(4-1):此時如果直接將tmp的值設定到b中,那麼將tmp轉換為包裝類後的值為2(a.valueOf(tmp),快取中存在,並且上一步已將快取中的值修改)

(4-2):重新例項化一個物件,而不是從快取池中獲取

在Integer中,有一個快取池(-128 到 127),呼叫valueOf前會先判斷是否命中快取池