???在 Java 中值類型和引用類型是如何進行傳遞的,這個是我今天要談論話題。
?????? 關于這個話題,我的一個好友的推薦下看了一篇文章,這才使我有了寫這篇文章的想法。這篇文章是《 Pass-by-Value Please 》 (http://www.javaranch.com/campfire/StoryPassBy.jsp) ,順便再向大家推薦一個網站,就是 http://www.javaranch.com ,一個很好的 Java 樂園。
?????? 好了,回到正題吧~免得一下又跑遠了~呵呵·
?????? 關于值類型,我想大家都很清楚了,總的說來就是 Copy the value and give it to you 。
??????
請看如下代碼:
?2?
?3?import?static?java.lang.System.out;
?4?
?5?public?class?PassByValue?{
?6?????public?static?void?testPassValue(){
?7?????????int?a?=?2?;
?8?????????int?b?=?a?;
?9?????????out.println("a=?"?+?a?)?;
10?????????out.println("b=?"?+?b?)?;
11?????????out.println("===============?the?value?has?changed?===============");
12?????????a?=?3?;??//?has?change?the?value?of?a,?but?tht?value?of?b?is?never?be?changed
13?????????out.println("a=?"?+?a?)?;
14?????????out.println("b=?"?+?b?)?;
15?????}
16?????
17?????public?static?void?main(String?[]?args){
18?????????out.println();
19?????????PassByValue.testPassValue();
20?????}
21?}
結果如下:
a= 2
b= 2
=============== the value has changed ===============
a= 3
b= 2
這個例子很明顯,不用過多的解釋, a 和 b 已經是兩個獨立的,互補相干的值。
下面進入我們今天的重點,關于引用類型。
我這里想借鑒一下我開篇提到的那篇文章,里面提到的杯子, I like the cap, do you?
在這里,我想打一個比方,把我們杯子里的引用 Reference 作一個類似,在操作系統里,有一個很重要的概念,那就是進程控制塊,他是進程實體的一部分,是操作系統中最重要的記錄型數據結構,他記錄了操作系統所需的,用于描述進程的當前情況以及控制進程運行的全部信息。同樣,引用也是如此,只是沒有這么復雜罷了。引用里存放了 java object 的相關信息,以便讓 JVM (Java Virtual Machine) 在堆中找到對象 (Java 對象全部在堆中 ) 。
我們可以把這種情況想象成在一個杯子里放了一個類似于進程控制塊的
reference
,下面來看如下代碼:
?2?
?3?import?static?java.lang.System.out;
?4?
?5?public?class?PassByValue?{
?6?????public?static?void?testPassValue(){
?7?????????int?a?=?2?;
?8?????????int?b?=?a?;
?9?????????out.println("a=?"?+?a?)?;
10?????????out.println("b=?"?+?b?)?;
11?????????out.println("===============?the?value?has?changed?===============");
12?????????a?=?3?;??//?has?change?the?value?of?a,?but?tht?value?of?b?is?never?be?changed
13?????????out.println("a=?"?+?a?)?;
14?????????out.println("b=?"?+?b?)?;
15?????}
16?????
17?????public?static?void?testPassReference(){
18?????????ObjectForTest?o1?=?new?ObjectForTest("Object?one");
19?????????ObjectForTest?o2?=?o1;
20?????????out.println(o1.getInfo());
21?????????out.println(o2.getInfo());
22?????????out.println("===============?the?value?has?changed?===============");
23?????????o1?=?new?ObjectForTest("Object?two");
24?????????out.println(o1.getInfo());
25?????????out.println(o2.getInfo());
26?????}
27?????
28?????public?static?void?main(String?[]?args){
29?????????out.println();
30?????????PassByValue.testPassValue();
31?????????out.println();
32?????????PassByValue.testPassReference();
33?????}
34?}
35?
36?class?ObjectForTest{
37?????String?info?;
38?????????
39?????public?ObjectForTest(){
40?????????info?=?"default";
41?????}
42?????????
43?????public?ObjectForTest(String?initInfo){
44?????????info?=?initInfo?;
45?????}
46?????????
47?????public?String?getInfo(){
48?????????return?info;
49?????}
50?????????
51?????public?void?setInfo(String?changeInfo){
52?????????info?=?changeInfo;
53?????}
54?}
運行結果是:
a= 2
b= 2
=============== the value has changed ===============
a= 3
b= 2
Object one
Object one
=============== the value has changed ===============
Object two
Object one
這里可以很明顯的表示出其實所謂的 Reference 其實就跟值類型是很相似的,所以我們可以給 Reference 取一個名字“引用值”。
這里只是把 o1 的引用值拷貝了一份給 o2 。
不過這里要注意的就是雖然是引用值的拷貝,但他們卻引用了同一個對象,任何一個對對象的改變都會,在另外一個引用上都可以顯示的出來。
看如下的例子:
?2?
?3?import?static?java.lang.System.out;
?4?
?5?public?class?PassByValue?{
?6?????public?static?void?testPassValue(){
?7?????????int?a?=?2?;
?8?????????int?b?=?a?;
?9?????????out.println("a=?"?+?a?)?;
10?????????out.println("b=?"?+?b?)?;
11?????????out.println("===============?the?value?has?changed?===============");
12?????????a?=?3?;??//?has?change?the?value?of?a,?but?tht?value?of?b?is?never?be?changed
13?????????out.println("a=?"?+?a?)?;
14?????????out.println("b=?"?+?b?)?;
15?????}
16?????
17?????public?static?void?testPassReference(){
18?????????ObjectForTest?o1?=?new?ObjectForTest("Object?one");
19?????????ObjectForTest?o2?=?o1;
20?????????out.println(o1.getInfo());
21?????????out.println(o2.getInfo());
22?????????out.println("===============?the?value?has?changed?===============");
23?????????o1?=?new?ObjectForTest("Object?two");
24?????????out.println(o1.getInfo());
25?????????out.println(o2.getInfo());
26?????}
27?????
28?????public?static?void?testChangeObject(){
29?????????ObjectForTest?o1?=?new?ObjectForTest("Object?one");
30?????????ObjectForTest?o2?=?o1;
31?????????out.println(o1.getInfo());
32?????????out.println(o2.getInfo());
33?????????out.println("===============?the?value?has?changed?===============");
34?????????o1.setInfo("Object?Value?changed!");
35?????????out.println(o1.getInfo());
36?????????out.println(o2.getInfo());
37?????}
38?????
39?????public?static?void?main(String?[]?args){
40?????????out.println();
41?????????PassByValue.testPassValue();
42?????????out.println();
43?????????PassByValue.testPassReference();
44?????????out.println();
45?????????PassByValue.testChangeObject();
46?????}
47?}
48?
49?class?ObjectForTest{
50?????String?info?;
51?????????
52?????public?ObjectForTest(){
53?????????info?=?"default";
54?????}
55?????????
56?????public?ObjectForTest(String?initInfo){
57?????????info?=?initInfo?;
58?????}
59?????????
60?????public?String?getInfo(){
61?????????return?info;
62?????}
63?????????
64?????public?void?setInfo(String?changeInfo){
65?????????info?=?changeInfo;
66?????}
67?}
結果如下:
a= 2
b= 2
=============== the value has changed ===============
a= 3
b= 2
Object one
Object one
=============== the value has changed ===============
Object two
Object one
Object one
Object one
=============== the value has changed ===============
Object Value changed
Object Value changed
從這里可以看到, o1 對對象的改變體現在了 o2 上了,通過對 o2 的調用可以看出。
以上是我對這個問題的看法,希望大家可以給一點幫助。
特別是testPassReference()這個方法,平時很容易犯錯...
我覺得平時寫程序盡量要避免這種寫法:P