示例一:面試
/** * 大廠面試題(微博、百度、騰訊): * 兩個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開闢新的內存空間,不會走緩存了