從陣列來看值傳遞和引用傳遞
慣例先看一段程式碼
public class DemoCollection14 {
public static void main(String[] args) {
String [] strs = {"zs", "ls", "wu"};
for (String str : strs) {
strs[0] = null;
System.out.println(str);
}
for (String str : strs) {
System.out.println(str);
}
}
}
//輸出:
// zs
// ls
// wu
//
// null
// ls
// wu
要想搞懂這道題,先看下面講解
重新學習陣列(此處引用了廖雪峰老師的講解)
基本型別陣列
陣列是引用型別,並且陣列大小不可變
public class Main {
public static void main(String[] args) {
// 5位同學的成績:
int[] ns;
ns = new int[] { 68, 79, 91, 85, 62 };
System.out.println(ns.length); // 5
ns = new int[] { 1, 2, 3 };
System.out.println(ns.length); // 3
}
}
陣列大小變了嗎?看上去好像是變了,但其實根本沒變。
對於陣列ns
來說,執行ns = new int[] { 68, 79, 91, 85, 62 };
時,它指向一個5個元素的陣列:
ns
│
▼
┌───┬───┬───┬───┬───┬───┬───┐
│ │68 │79 │91 │85 │62 │ │
└───┴───┴───┴───┴───┴───┴───┘
執行ns = new int[] { 1, 2, 3 };
時,它指向一個新的3個元素的陣列:
ns ──────────────────────┐
│
▼
┌───┬───┬───┬───┬───┬───┬───┬───┬───┬───┬───┐
│ │68 │79 │91 │85 │62 │ │ 1 │ 2 │ 3 │ │
└───┴───┴───┴───┴───┴───┴───┴───┴───┴───┴───┘
但是,原有的5個元素的陣列並沒有改變,只是無法通過變數ns
引用到它們而已。
字串陣列
如果陣列元素不是基本型別,而是一個引用型別,那麼,修改陣列元素會有哪些不同?
字串是引用型別,因此我們先定義一個字串陣列:
String[] names = {
"ABC", "XYZ", "zoo"
};
對於String[]
型別的陣列變數names
,它實際上包含3個元素,但每個元素都指向某個字串物件:
┌─────────────────────────┐
names │ ┌─────────────────────┼───────────┐
│ │ │ │ │
▼ │ │ ▼ ▼
┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┐
│ │░░░│░░░│░░░│ │ "ABC" │ │ "XYZ" │ │ "zoo" │ │
└───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┘
│ ▲
└─────────────────┘
對names[1]
進行賦值,例如names[1] = "cat";
,效果如下:
┌─────────────────────────────────────────────────┐
names │ ┌─────────────────────────────────┐ │
│ │ │ │ │
▼ │ │ ▼ ▼
┌───┬───┬─┴─┬─┴─┬───┬───────┬───┬───────┬───┬───────┬───┬───────┬───┐
│ │░░░│░░░│░░░│ │ "ABC" │ │ "XYZ" │ │ "zoo" │ │ "cat" │ │
└───┴─┬─┴───┴───┴───┴───────┴───┴───────┴───┴───────┴───┴───────┴───┘
│ ▲
└─────────────────┘
這裡注意到原來names[1]
指向的字串"XYZ"
並沒有改變,僅僅是將names[1]
的引用從指向"XYZ"
改成了指向"cat"
,其結果是字串"XYZ"
再也無法通過names[1]
訪問到了。
對“指向”有了更深入的理解後,試解釋如下程式碼:
public class Main {
public static void main(String[] args) {
String[] names = {"ABC", "XYZ", "zoo"};
String s = names[1];
names[1] = "cat";
System.out.println(s); // s是"XYZ"還是"cat"?
}
}
//輸出"XYZ"
//解釋原因:
//names字串陣列建立好後,s指向names[1]這個位置。
//但是呢,name[1]可不是把原資料XYZ更改為了cat,而是重新指向了存有cat的那個空間地址。
//故s還是指向原來那個位置,故輸出的是XYZ
再回到開始的那個問題:
public class DemoCollection14 {
public static void main(String[] args) {
String [] strs = {"zs", "ls", "wu"};
for (String str : strs) {
strs[0] = null;
System.out.println(str);
}
for (String str : strs) {
System.out.println(str);
}
}
}
//輸出:
// zs
// ls
// wu
//
// null
// ls
// wu
foreach,其實就是迭代器。迭代器,不是傳統意義的for迴圈輸出陣列資料。
而是定義了String str,依次str=strs[i],並輸出str。故和前面的xyz,性質一樣了。