兩個Integer的引用對象傳遞給一個swap方法的內部進行交換,返回後,兩個引用的值是否會發生變化

示例一:面試

/**
 * 大廠面試題(微博、百度、騰訊):
 *      兩個Integer的引用對象傳遞給一個swap方法的內部進行交換,返回後,兩個引用的值是否會發生變化
 */
public class Test001 {
    public static void main(String[] args) {
        Integer a=1,b=2;
        //a=Integer@533=1,b=Integer@534=2
        System.out.println("before:a="+a+",b="+b);
        swap(a,b);
        //a=Integer@533=1,b=Integer@534=2
        System.out.println("after:a="+a+",b="+b);
    }
    private static void swap(Integer i1, Integer i2) {
        //tmp=i1=Integer@533---1
        Integer tmp=i1;
        //i1=i2=Integer534@--2
        i1=i2;
        //i2=tmp=i1=Integer@533----1
        i2=tmp;
    }

輸出結果:數組

數組元素做爲函數的實參時,用法跟普通變量做參數相同,將數組元素的值傳遞給形參時進行函數體調用,函數調用完返回後,數組元素的值不變。這種傳遞方式是」值傳遞「方式,即只能從實參傳遞給形參,而不能從形參傳遞給實參緩存

咱們經過Java反編譯工具查看,底層經過Integer.valueOf()來轉換函數

咱們經過源碼來看看valueOf()方法實現原理工具

public static Integer valueOf(int i) {
    //若是是在Integer緩存中-128到127之間則去緩存中取值
 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)];
    //不然直接開闢一個新的內存空間
    return new Integer(i);
}
private static class IntegerCache {
    static final int low = -128;
    static final int high;
    static final Integer cache[];//緩存數組

.....
}

咱們Integer a=1,b=2在Integer緩存範圍以內,因此走 return IntegerCache.cache[i + (-IntegerCache.low)];去緩存數組中拿值spa

線程對變量的全部操做(讀取、賦值)都必須在工做內存中進行,而不能直接讀寫主內存中的變量。在swap方法內部交換引用,只會交換線程的工做內存中持有的方法參數,線程

而工做內存中的方法參數是主內存中變量的副本,所以執行這樣的swap方法不會改變主內存中變量的指向  對象

案例二:blog

public class Test002 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Integer a=1,b=2;
        //a=Integer@534=1,b=Integer@535=2
        System.out.println("before:a="+a+",b="+b);
        swap(a,b);
        //a=Integer@534=2,b=Integer@535=2
        System.out.println("after:a="+a+",b="+b);
    }
    private static void swap(Integer i1, Integer i2) throws NoSuchFieldException, IllegalAccessException {
      //反射獲取成員變量
        Field value = Integer.class.getDeclaredField("value");
        value.setAccessible(true);
        //tmp=1
        int tmp=i1.intValue();
        //i1=Integer@534=2
        value.set(i1,i2.intValue());
        //i2=Integer@535=tmp=i1.intValue()=2
        value.set(i2,tmp);
    }

輸出結果內存

使用反射機制,傳遞的是數組元素對應的地址,這樣形參數組和實參數組共佔用一段內存單元,當形參值發生變化時,實參值也發生變化。

查看反編譯結果

private final int value;

交換的是引用地址,修改爲員變量final value的值,可用經過反射機制修改。

public static Integer valueOf(int i) {
 if (i >= IntegerCache.low && i <= IntegerCache.high) return IntegerCache.cache[i + (-IntegerCache.low)];
    return new Integer(i);
}

仍是會去Integer緩存數組中找到這個值2,並設置給 i1,由於tmp=i1.intValue(),棧中的tmp的地址會指向Integer在堆中數組對應值爲i1的地址,因此

通過 value.set(i1, Integer.valueOf(i2.intValue()));以後,tmp就=2,最後 value.set(i2, Integer.valueOf(tmp));將2賦值給 i2.

案例三:

public class Test003 {
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        Integer a=1,b=2;
        //a=Integer@534=1,b=Integer@535=2
        System.out.println("before:a="+a+",b="+b);
        swap(a,b);
        //a=Integer@534=2,b=Integer@535=1
        System.out.println("after:a="+a+",b="+b);
    }
    private static void swap(Integer i1, Integer i2) throws NoSuchFieldException, IllegalAccessException {
        //反射獲取成員變量
        Field value = Integer.class.getDeclaredField("value");
        value.setAccessible(true);
        //從新開闢一個內存空間
        //tmp=Integer@545=1
        Integer tmp=new Integer(i1.intValue());
        //i1=Integer@534=2
        value.set(i1,i2.intValue());
        //i2=Integer@535=tmp=new Integer(i1.intValue())=1
        value.set(i2,tmp);

    }
}

輸出結果爲:

這裏總總結前面的經驗,new Integer開闢新的內存空間,不會走緩存了

相關文章
相關標籤/搜索