Java 引用傳遞與值傳遞

Java 引用傳遞與值傳遞

【背景】

首先 Java 中沒有值傳遞和引用傳遞的概念,所謂 pass by value 和 pass by reference 只是從其他語言引申的概念而已。所以你會聽到有人說 ”Java 中沒有引用傳遞,全部都是值傳遞“,然而在使用過程中卻又總能遇到 ”方法調用確實改變了某些值“ 的情況。

一、基本類型與引用類型

基本類型:byte/char/int/long/float/double

引用類型:除了上述類型之外的類型,包括各種擴展類型(Integer/Character/Double等),String,實體類,List 等;

int num = 10;
String str = "hello";
num - 10
str - 0x11
hello

​ 如圖所示,num是基本類型,值就直接保存在變量中。而str是引用類型,變量中保存的只是實際對象的地址。一般稱這種變量爲"引用",引用指向實際對象,實際對象中保存着內容。

二、賦值運算符 ”=“

​ 當使用賦值運算符時,會發生什麼?

num = 20;
str = "word";
num - 20
0x11
hello
str - 0x12
word

​ 對於基本類型,賦值直接改變了值。對於引用類型而言,new了一個新對象 word,並將str中保存的地址更新爲了新的地址。由於原地址0x11不再持有任何引用,(0x11 -> hello) 會被垃圾回收掉。

三、方法調用時發生了什麼

// 第一個例子:基本類型
void foo(int value) {
    value = 100;
}
// num 沒有被改變
foo(num);

// 第二個例子:沒有提供改變自身方法的引用類型
void foo(String text) {
    text = "windows";
}
// str 也沒有被改變
foo(str);

// 第三個例子:提供了改變自身方法的引用類型
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder.append("11pro");
}
// sb 被改變了,變成了"iphone11pro"
foo(sb); 

// 第四個例子:提供了改變自身方法的引用類型,但是不使用,而是使用賦值運算符。
StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
    builder = new StringBuilder("ipad");
}
// sb 沒有被改變,還是 "iphone"。
foo(sb); 

// 第五個例子:List
List<User> userList = new ArrayList<>();
void foo(List<User> list) {
    // 有效
    userList.add(new User("aaaaa", 2));
    userList = new ArrayList<>();
    // 無效
    userList.add(new User("bbbbb",1));
}


/*
	【總結】
	1. 使用 = 對方法參數賦值的,都不能改變調用者的值
	2. 使用引用類型提供的改變自身的方法 (如 List.add(); StringBuilder.append(); )
			可以改變其值 (類似引用傳遞)
*/

四、都是這樣的嗎

int[][] arr3 = new int[3][3];
setArr(arr3);
private static void setArr(int[][] arr3) {
    // 有效
    arr3[2][1] = 1;
    // 有效
    arr3[1] = new int[] {1,2,3};
    // 無效
    arr3 = new int[5][6];
}

不能完全按照 ”=“ 操作來判斷是否爲 ”引用傳遞“ 。 因爲在以上代碼中,實例化的二維數組中,arr3 處保存了一個地址(棧區),指向了其實際值的位置(堆區)。

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