Java值傳遞和引用_第1頁
Java值傳遞和引用_第2頁
Java值傳遞和引用_第3頁
Java值傳遞和引用_第4頁
Java值傳遞和引用_第5頁
已閱讀5頁,還剩1頁未讀 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、java語言深入(java中是傳值還是引用)關(guān)鍵字: java基礎(chǔ)深入 熟悉C的程序員都用過指針,對指針可謂愛之深恨之切。指針是指向一塊內(nèi)存地址的內(nèi)存數(shù)據(jù)(有些拗口),也就是說指針本身是一個占用4字節(jié)內(nèi)存的 int(32 位系統(tǒng)內(nèi)),而這個int值恰恰又是另一塊內(nèi)存的地址。比如hello這個字串,存放在0x0000F000這個地址到 0x0000F005這段內(nèi)存區(qū)域內(nèi)(包括0x00的結(jié)束字節(jié))。而在0x0000FFF0到0x0000FFF03這四個字節(jié)內(nèi)存放著一個 int,這個int的值是 0x0000F000。這樣就形成了一個指向hello字串的指針。 在Java中,很多人說沒有指針,事實上

2、,在Java更深層次里,到處都是大師封裝好的精美絕倫的指針。為了更容易的講解Java中關(guān)于類和類型的調(diào)用,Java中出現(xiàn)了值與引用的說法。淺顯的來說,我們可以認(rèn)為 Java中的引用與C中的指針等效(其實差別非常非常大,但是為了說明我們今天的問題,把他們理解為等效是沒有任何問題的)。 所謂傳引用的說法是為了更好的講解調(diào)用方式?;谏厦鎸χ羔樀睦斫?,我們不難看出,指針其實也是一個int值,所謂傳引用,我們是復(fù)制了復(fù)制了指針的 int值進(jìn)行傳遞。為了便于理解,我們可以姑且把指針看作一種數(shù)據(jù)類型,透明化指針的int特性,從而提出傳引用的概念。 重申一遍:Java中只有傳值。 1所謂傳值和傳引用 傳值和

3、傳引用的問題一直是Java里爭論的話題。與C+不同的,Java里面沒有指針的概念,Java的設(shè)計者巧妙的對指針的操作進(jìn)行了管理。事實上,在懂C+的Java程序員眼中,Java到處都是精美絕倫的指針。 下面舉個簡單的例子,說明什么是傳值,什么是傳引用。 /例1 void method1() int x=0; this.change(x); System.out.println(x); void int change(int i) i=1; 很顯然的,在mothod1中執(zhí)行了change(x)后,x的值并不會因為change方法中將輸入?yún)?shù)賦值為1而變成1,也就是說在執(zhí)行change(x)后,x的

4、值z依然是0。這是因為x傳遞給change(int i)的是值。這就是最簡單的傳值。 同樣的,進(jìn)行一點簡單的變化。 /例2 void method1() StringBuffer x=new StringBuffer(Hello); this.change(x); System.out.println(x); void int change(StringBuffer i) i.append( world!); 看起來沒什么變化,但是這次mothed1中執(zhí)行了change (x)后,x的值不再是Hello了,而是變成了Hello world!。這是因為x傳遞給change(i)的是x的引用。這是

5、最經(jīng)典的傳引用。 似乎有些奇怪了,兩段程序沒有特別的不同,可是為什么一個傳的是值而另一個傳的是引用呢?. 2非要搞清楚傳值還是傳引用的問題嗎? 搞清楚這自然是有必要的,不然我也不需要寫這么多了,不過的確沒有到非要的地步。 首先,如果我們不太關(guān)心什么是傳值什么是傳引用,我們一樣能寫出漂亮的代碼,但是這些代碼在運行過程中可能會存在著極大的隱患。 全局變量是讓大家深惡痛絕(又難以割舍)的東西,原因就是使用全局變量要特別注意數(shù)據(jù)的保護(hù)。如果在多線程的程序里使用全局變量簡直就等于跟自己過不去。不了解傳值和傳引用的問題,跟使用全局變量不考慮數(shù)據(jù)保護(hù)的罪過是不相上下下的,甚至有時候比它還要糟。你會莫名其妙,

6、為什么我的返回參數(shù)沒有起作用,為什么我傳進(jìn)去的參數(shù)變成了這樣.? 一個例子: /例3 void mothed1() int x=0; int y=1; switchValue(x,y); System.out.println(x=+x); System.out.println(y=+y); void switchValue(int a,int b) int c=a; a=b; b=c; 上面是一個交換a,b值的函數(shù),看起來似乎蠻正確的,但是這個函數(shù)永遠(yuǎn)也不會完成你想要的工作。 還有一個例子: /例4 StringBuffer a=new StringBuffer(I am a ); Strin

7、gBuffer b=a; a.append(after append); a=b; System.out.println(a=+a); 在編程過程中,經(jīng)常會遇到這種情況,一個變量的值要被臨時改變一下,等用完之后再恢復(fù)到開始的值。就好像上面的例子,a為了保持它的值,使用b=a做賦值,之后a被改變,再之后a把暫存在b里面的值取回來。這是我們一廂情愿的想法,而事實上,這段代碼執(zhí)行后,你會發(fā)現(xiàn)a的值已經(jīng)改變了。 以上是兩個最簡單的例子,真正的程序開發(fā)過程中,比這要復(fù)雜的情況每天都會遇到。 3類型和類 Java 提出的思想,在Java里面任何東西都是類。但是Java里面同時還有簡單數(shù)據(jù)類型:int,by

8、te,char,boolean,與這些數(shù)據(jù)類型相對應(yīng)的類是Integer,Byte,Character,Boolean,這樣做依然不會破壞Java關(guān)于任何東西都是類的提法。 這里提到數(shù)據(jù)類型和類似乎和我們要說的傳值和傳引用的問題無關(guān),但這是我們分辨?zhèn)髦岛蛡饕玫幕A(chǔ)。 4試圖分辨?zhèn)髦颠€是傳引用 為什么是試圖分辨呢?很簡單,傳值和傳引用的問題無處不在,但是似乎還沒有人能正統(tǒng)的給出標(biāo)準(zhǔn),怎樣的就是值拷貝調(diào)用,怎樣的就是引用調(diào)用。面對這個問題,我們更多的應(yīng)該是來自平時積累對Java的理解。 回過頭來,我們分析一下上面的幾個例子: 先看例1,即使你不明白為什么,但是你應(yīng)該知道這樣做肯定不會改變x的值。

9、為了方便說明,我們給例子都加上行號。 /例1 1 void method1() 2 int x=0; 3 this.change(x); 4 5 6 void int change(int i) 7 i=7; 8 讓我們從內(nèi)存的存儲方式看一下x和I之間到底是什么關(guān)系。 在執(zhí)行到第2行的時候,變量x指向一個存放著int 0的內(nèi)存地址。 變量x-存放值0 執(zhí)行第3行調(diào)用change(x)方法的時候,內(nèi)存中是這樣的情形:x把自己值在內(nèi)存中復(fù)制一份,然后變量i指向這個被復(fù)制出來的0。 變量x-存放值0 進(jìn)行了一次值復(fù)制 變量x-存放值0 這時候再執(zhí)行到第7行的時候,變量i的被賦值為7,而這一步的操作已

10、經(jīng)跟x沒有任何關(guān)系了。 變量x-存放值0 變量x-存放值7 說到這里應(yīng)該已經(jīng)理解為什么change(x)不能改變x的值了吧?因為這個例子是傳值的。 那么,試著分析一下為什么例三中的switchValue()方法不能完成變量值交換的工作? 再看例2。 /例2 1void method1() 2 StringBuffer x=new StringBuffer(Hello); 3 this.change(x); 4 5 6void int change(StringBuffer i) 7 i.append( world!); 8 例2似乎和例1從代碼上看不出什么差別,但是執(zhí)行結(jié)果卻是change(x

11、)能改變x的值。依然才從內(nèi)存的存儲角度來看看例2的蹊蹺在哪里。 在執(zhí)行到第2行時候,同例1一樣,x指向一個存放Hello的內(nèi)存空間。 變量x-存放值Hello 接下來執(zhí)行第三行change(x),注意,這里就與例1有了本質(zhì)的不同:調(diào)用change(x)時,變量i也指向了x指向的內(nèi)存空間,而不是指向x的一個拷貝。 變量x -存放值Hello 變量x / 于是,第7行對i調(diào)用append方法,改變i指向的內(nèi)存空間的值,x的值也就隨之改變了。 變量x -追加為Hello World! 變量x / 為什么x值能改變呢?因為這個例子是傳引用的。 這幾個例子是明白了,可是很多人會開始有另一個疑問了:這樣看

12、來,到底什么時候是傳的值什么時候是傳得引用呢?于是,我們前面講到的類型和類在這里就派上了用場:對于參數(shù)傳遞,如果是簡單數(shù)據(jù)類型,那么它傳遞的是值拷貝,對于類的實例它傳遞的是類的引用。需要注意的是,這條規(guī)則只適用于參數(shù)傳遞。為什么這么說呢?我們看看這樣一個例子: /例5 String str=abcdefghijk; str.replaceAll(b,B); 這兩句執(zhí)行后,str的內(nèi)容依然是abcdefghijk,但是我們明明是對str操作的,為什么是這樣的呢?因為str的值究竟會不會被改變完全取決于replaceAll這個方法是怎么實現(xiàn)的。類似的,有這樣一個例子: /例6 1 void met

13、hod1() 2 StringBuffer x = new StringBuffer(Hello); 3 change1(x); 4 System.out.println(x); 5 6 7 void method2() 8 StringBuffer x = new StringBuffer(Hello); 9 change2(x); 10 System.out.println(x); 11 12 13 void change1(StringBuffer sb) 14 sb.append( world!); 15 16 17 void change2(StringBuffer sb) 18 s

14、b = new StringBuffer(hi); 19 sb.append( world!); 20 調(diào)用method1(),屏幕打印結(jié)果為:Hello world! 調(diào)用method2(),我們認(rèn)為結(jié)果應(yīng)該是hi world,因為sb傳進(jìn)來的是引用??墒菍嶋H執(zhí)行的結(jié)果是Hello! 難道change2()又變成傳值了?!其實change1()和change2()的確都是通過參數(shù)傳入引用,但是在方法內(nèi)部因為處理方法的不同而使結(jié)果大相徑庭。我們還是從內(nèi)存的角度分析: 執(zhí)行method1()和change1()不用再多說了,上面的例子已經(jīng)講解過,這里我們分析一下method2()和change2

15、()。 程序執(zhí)行到第8行,x指向一個存放著Hello的內(nèi)存空間。 變量x-存放值Hello 第9行調(diào)用change2,將sb指向x指向的內(nèi)存空間,也就是傳入x的引用。 變量x -存放值Hello 變量x / 到這里為止還沒有什么異樣,接下來執(zhí)行18行,這里就出現(xiàn)了類似傳入值拷貝的變化:new 方法并沒有改變sb指向內(nèi)存的內(nèi)容,而是在內(nèi)從中開辟了一塊新的空間存放串hi,同時sb指向了這塊空間。 變量x-存放值Hello 原有的引用被切斷 變量x-另一塊存放hi的空間 接下來再對sb進(jìn)行append已經(jīng)和x沒有任何關(guān)系了。 所以,還有一條不成規(guī)則的規(guī)則:對于函數(shù)調(diào)用,最終效果是什么完全看函數(shù)內(nèi)部的

16、實現(xiàn)。比較標(biāo)準(zhǔn)的做法是如果會改變引用的內(nèi)容,則使用void作為方法返回值,而不會改變引用內(nèi)容的則在返回值中返回新的值。 雖然已經(jīng)說了這么多,但是感覺傳值還是傳引用的問題依然沒有完全說清楚。因為這個問題本身就是很難歸納總結(jié)的問題,所以更多的理解要靠平時的積累和形成。下面幾個例子,給大家嘗試進(jìn)行分析。 /例7,打印結(jié)果是什么? public static void main(String args) int a; int b; StringBuffer c; StringBuffer d; a = 0; b = a; c = new StringBuffer(This is c); d = c;

17、a = 2; c.append(!); System.out.println(a= + a); System.out.println(b= + b); System.out.println(c= + c); System.out.println(d= + d); /例8,打印結(jié)果是什么? public class Test public static void main(String args) StringBuffer sb = new StringBuffer(Hello ); System.out.println(Before change, sb = + sb); changeData(sb); System.out.println(After changeData(n), sb = + sb); public static void changeData(StringBuffer strBuf) StringBuffer sb2 = new StringBuffer(Hi ); strBuf = sb2; sb2.append(World!); 如果是以基本數(shù)據(jù)類型(包括String類)做參數(shù)進(jìn)行傳遞,或以某個類名(包括數(shù)組名)為類型做為參數(shù)而直接對其

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論