作者brianhsu (坟墓)
看板java
标题Re: [问题] 请教一个基本的问题
时间Fri Dec 4 07:36:55 2009
※ 引述《sbrhsieh (偶尔想摆烂一下)》之铭言:
: 实际上把 adrianshum 提出的例子改成 formal parameter: a 只有单纯的
: assignment 操作,还是会有人搞错,因此 adrianshum 的例子重点不在於
: Java String (某种程度来说)是 immutable object。
: 每次出现 call by reference/call by value 的讨论时,总是会出现许许多多
: 的 Java sample code,甚至 C/C++ 的 sample code,争论了半天认为 Java 是
: call by reference 到最後还是不能体会说 Java 只有 call by value 的人为
: 什麽会如此宣称。
闲闲没事,我又来了,这次我要学 adrianshum 来话图。
另外,其实我一直觉得宣称 Java 是 call by reference 根本就是
在误导……字串的那个例子就很明显了。
谜之声:如果觉得这字串只是特例,我还是觉得那麽一定是基础观念
不清楚啊!因为就算不是字串,还是可以造成相同效果滴。
class A {
public int x = 5;
}
public class Test {
void fun (A test)
{
test.x = 3;
return;
}
public static void main (String [] args) {
A test = new A ();
fun (test);
System.out.println ("test.x:" + test.x);
}
}
整个程式的流程是 main -> fun -> main,这应该很清楚,没有什特
别的,但问题是,每个一步下来,到底你的 reference、物件都放在
哪,生命周期有多长吗?如果可以回答的出来,其实管他是什麽型态
的物件,或是基本资料型态,都不会搞混的。
重点:真要说的话,Java 的 function 只有 call by value ,根本
就没有 call by reference 这一回事!
以下是流程:
===================================================================
1. A test = new A () // Heap 上长一个 A 物件,Stack 上长一个
// 名叫 test 的 reference 指到刚刚的 A
Stack Heap
+-------+ +--------+
main()| test | --------> | A{x=5} |
+-------+ +--------+
==================================================================
2. fun (test) // 这一步是重点,实际上是 stack 多了另一个 test,
// 只是恰巧指到同一个物件啊!
Stack Heap
+-------+
fun() | test |----------------------------+
+-------+ +--------+ |
main()| test | --------> | A{x=5} | <-----+
+-------+ +--------+
===================================================================
3. test.x = 5 // 把 fun() 里的 test 指到的物件的 x 栏位改成 3
Stack Heap
+-------+
fun() | test |----------------------------+
+-------+ +--------+ |
main()| test | --------> | A{x=3} | <-----+
+-------+ +--------+
====================================================================
4. return // 这句有没有都没差,重点是 return 的时候最上层的
// test 立刻就消灭啦!
Stack Heap
+-------+ +--------+
main()| test | --------> | A{x=3} |
+-------+ +--------+
====================================================================
5. System.out.println.... // 印出来的 test 指到的当然是 3
====================================================================
以上,是常见的『伪 call by reference』范例,但换下面这个例子就很清
楚了。
如果把 fun 改成像下面:
void fun (A test)
{
test = new A();
test.x = 3
}
为什麽最後印出来的会是 5 而不是 3?因为在呼叫到 fun 的时候,记忆
体里是长这个模样的:
==================================================================
1. fun (test) // 这边一开始都一样
Stack Heap
+-------+
fun() | test |----------------------------+
+-------+ +--------+ |
main()| test | --------> | A{x=5} | <-----+
+-------+ +--------+
==================================================================
2. test = new A(); // 现在 fun() 的 test 和 main() 的 test 指到的
// 根本是不同的物件啊!
Stack Heap
+-------+ +--------+
fun() | test |---------> | A{x=5} |
+-------+ +--------+
main()| test | --------> | A{x=5} |
+-------+ +--------+
==================================================================
3. test.x = 3; // 把 fun() 的 test 指到的物件的 x 栏位改成 3
Stack Heap
+-------+ +--------+
fun() | test |---------> | A{x=3} |
+-------+ +--------+
main()| test | --------> | A{x=5} |
+-------+ +--------+
==================================================================
3. return; // fun() 的 test 被消灭了!
// x = 3 的那个物件变孤儿,可以被 GC 回收
Stack Heap
+--------+
| A{x=3} | // 我变垃圾了……囧!
+-------+ +--------+
main()| test | --------> | A{x=5} |
+-------+ +--------+
==================================================================
4. System.out.pritnln... // main () 里的 test 指到的东西一
// 直都没变过,当然是 5 啊!
==================================================================
以上。
至於为什麽像是 adrianshum 指出的
void fun(String a)
{
a += "foo";
}
会产生和第二个 case 一样的状况,那就是因为 String 本身是不
可变的,所以上面的 function 可以视同(不完全正确)会被翻译
成:
void fun(String a)
{
a = new String(......)
}
没错,我们又把 a 指到另一个完全不同的物件!所以变成和上述
的第二个例子一样了。
--
~
白马带着她一步步地回到中原。白马已经老了,只能慢慢地走,
'v'
Brian Hsu 但终是能回到中原的。江南有杨柳、桃花,有燕子、金鱼……
// \\
( 坟 墓 )
/( )\
但这个美丽的姑娘就像古高昌国人那样固执。 【白马啸西风】
^`~'^
http://bone.twbbs.org.tw/blog 『那都是很好很好的,可我偏不喜欢。』
--
※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 59.120.199.114
※ 编辑: brianhsu 来自: 59.120.199.114 (12/04 07:37)
※ 编辑: brianhsu 来自: 59.120.199.114 (12/04 07:37)