初學者最易混淆的點:**對象**與**對象引用**是兩個完全不同的實體。**引用不是對象**,它只是指向對象的「繩子」。
new Vehicle() = 吹一個新氣球Vehicle v = new Vehicle() = 吹氣球並用繩子 v 系住v = null = 解開繩子,氣球飛走(成為垃圾回收候選者)v2 = v = 另一根繩子 v2 也系住同一個氣球Vehicle v1 = new Vehicle(); // 繩子 v1 系住氣球 A
Vehicle v2 = v1; // 繩子 v2 也系住氣球 A(複製的是繩子,非氣球)
v2 = new Vehicle(); // v2 改系氣球 B,氣球 A 仍被 v1 系住
v1 = v2; // v1 也改系氣球 B,氣球 A 無繩子系住 → 等待 GC 回收
new Vehicle(); // 臨時對象:吹氣球不系繩子,用完即丟(如 System.out.println("xxx"))
== 比較引用(繩子是否系同一氣球),equals() 比較內容(氣球長得像不像)public class ParamTest {
// 基本類型:傳值副本
static void testBasic(int m) { m = 100; }
// 引用類型不改變引用指向:影響原對象
static void add(StringBuffer s) { s.append("_add"); }
// 引用類型改變引用指向:不影響原對象
static void changeRef(StringBuffer s) { s = new StringBuffer("Java"); }
public static void main(String[] args) {
int i = 50; testBasic(i); // i 仍為 50
StringBuffer sb = new StringBuffer("init");
add(sb); // sb 變為 "init_add"(同一氣球被修改)
changeRef(sb); // sb 仍為 "init_add"(換了根繩子系新氣球,原氣球不變)
}
}
本質:傳遞引用時,複製的是「繩子」(引用值/地址)。方法內修改對象內容 → 影響外部;方法內讓引用指向新對象 → 不影響外部。
public class Test {
public int i, j;
// 情況 1:方法內 new 新對象並讓參數指向它
public void test_m(Test a) {
Test b = new Test(); b.i=1; b.j=2;
a = b; // 參數 a 換繩子系住 b,外部 t 不受影響
}
// 情況 2:直接修改參數指向的對象屬性
public void test_m1(Test a) { a.i=1; a.j=2; } // 影響外部 t
public static void main(String[] args) {
Test t = new Test(); t.i=5; t.j=6;
t.test_m(t); // t 仍為 5,6
t.test_m1(t); // t 變為 1,2
}
}
A a1 = new A();→ A 是類,a1 是引用,new A() 是對象
=不是賦值,是傳地址:右邊對象地址傳給左邊引用
引用本質 = 指針(存地址),Java 表面無指針,實則皆指針
String s1 = "AAAA";
String s2 = s1; // s2 系住同一氣球
s1 = "BBBB"; // s1 換繩子系新氣球 "BBBB",s2 仍系 "AAAA"
// String 不可變,任何「修改」實質都是新建對象
理解「引用傳遞的是地址值」,就能秒懂所有 Java 參數傳遞、賦值、GC 行為。