JAVA引用和對象的關(guān)系,還有值傳遞_第1頁
JAVA引用和對象的關(guān)系,還有值傳遞_第2頁
JAVA引用和對象的關(guān)系,還有值傳遞_第3頁
JAVA引用和對象的關(guān)系,還有值傳遞_第4頁
全文預覽已結(jié)束

下載本文檔

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

文檔簡介

1、Java對象及其引用關(guān)鍵字: java對象引用 Java對象及其引用 關(guān)于對象與引用之間的一些基本概念。 初學Java時,在很長一段時間里,總覺得基本概念很模糊。后來才知道,在許多Java書中,把對象和對象的引用混為一談??墒?,如果我分不清對象與對象引用, 那實在沒法很好地理解下面的面向?qū)ο蠹夹g(shù)。把自己的一點認識寫下來,或許能讓初學Java的朋友們少走一點彎路。 為便于說明,我們先定義一個簡單的類:class Vehicle int passengers; int fuelcap; int mpg; 有了這個模板,就可以用它來創(chuàng)建對象: Vehicle veh1 = new Vehicle()

2、; 通常把這條語句的動作稱之為創(chuàng)建一個對象,其實,它包含了四個動作。 1)右邊的“new Vehicle”,是以Vehicle類為模板,在堆空間里創(chuàng)建一個Vehicle類對象(也簡稱為Vehicle對象)。 2)末尾的()意味著,在對象創(chuàng)建后,立即調(diào)用Vehicle類的構(gòu)造函數(shù),對剛生成的對象進行初始化。構(gòu)造函數(shù)是肯定有的。如果你沒寫,Java會給你補上一個默認的構(gòu)造函數(shù)。3)左邊的“Vehicle veh1”創(chuàng)建了一個Vehicle類引用變量。所謂Vehicle類引用,就是以后可以用來指向Vehicle對象的對象引用。 4)“=”操作符使對象引用指向剛創(chuàng)建的那個Vehicle對象。 我們可以

3、把這條語句拆成兩部分:Vehicle veh1; veh1 = new Vehicle(); 效果是一樣的。這樣寫,就比較清楚了,有兩個實體:一是對象引用變量,一是對象本身。 在堆空間里創(chuàng)建的實體,與在數(shù)據(jù)段以及??臻g里創(chuàng)建的實體不同。盡管它們也是確確實實存在的實體,但是,我們看不見,也摸不著。不僅如此,我們仔細研究一下第二句,找找剛創(chuàng)建的對象叫什么名字?有人說,它叫“Vehicle”。不對,“Vehicle”是類(對象的創(chuàng)建模板)的名字。 一個Vehicle類可以據(jù)此創(chuàng)建出無數(shù)個對象,這些對象不可能全叫“Vehicle”。 對象連名都沒有,沒法直接訪問它。我們只能通過對象引用來間接訪問對象。

4、 為了形象地說明對象、引用及它們之間的關(guān)系,可以做一個或許不很妥當?shù)谋扔?。對象好比是一只很大的氣球,大到我們抓不住它。引用變量是一根繩, 可以用來系汽球。 如果只執(zhí)行了第一條語句,還沒執(zhí)行第二條,此時創(chuàng)建的引用變量veh1還沒指向任何一個對象,它的值是null。引用變量可以指向某個對象,或者為null。 它是一根繩,一根還沒有系上任何一個汽球的繩。執(zhí)行了第二句后,一只新汽球做出來了,并被系在veh1這根繩上。我們抓住這根繩,就等于抓住了那只汽球。 再來一句:Vehicle veh2;就又做了一根繩,還沒系上汽球。如果再加一句: veh2 = veh1; 系上了。這里,發(fā)生了復制行為。但是,要說

5、明的是,對象本身并沒有被復制,被復制的只是對象引用。結(jié)果是,veh2也指向了veh1所指向的對象。兩根繩系的是同一只汽球。 如果用下句再創(chuàng)建一個對象: veh2 = new Vehicle();則引用變量veh2改指向第二個對象。從以上敘述再推演下去,我們可以獲得以下結(jié)論:(1)一個對象引用可以指向0個或1個對象(一根繩子可以不系汽球,也可以系一個汽球); (2)一個對象可以有N個引用指向它(可以有N條繩子系住一個汽球)。 如果再來下面語句: veh1 = veh2; 按上面的推斷,veh1也指向了第二個對象。這個沒問題。問題是第一個對象呢?沒有一條繩子系住它,它飛了。多數(shù)書里說,它被Java

6、的垃圾回收機制回收了。 這不確切。正確地說,它已成為垃圾回收機制的處理對象。至于什么時候真正被回收,那要看垃圾回收機制的心情了。 由此看來,下面的語句應該不合法吧?至少是沒用的new Vehicle(); 不對。它是合法的,而且可用的。譬如,如果我們僅僅為了打印而生成一個對象,就不需要用引用變量來系住它。最常見的就是打印字符串:System.out.println(“I am Java!”); 字符串對象“I am Java!”在打印后即被丟棄。有人把這種對象稱之為臨時對象。對象與引用的關(guān)系將持續(xù)到對象回收。 Java對象及引用 Java對象及引用是容易混淆卻又必須掌握的基礎(chǔ)知識,本章闡述Ja

7、va對象和引用的概念,以及與其密切相關(guān)的參數(shù)傳遞。 先看下面的程序:StringBuffer s; s = new StringBuffer(Hello World!); 第一個語句僅為引用(reference)分配了空間,而第二個語句則通過調(diào)用類(StringBuffer)的構(gòu)造函數(shù)StringBuffer(String str)為類生成了一個實例(或稱為對象)。這兩個操作被完成后,對象的內(nèi)容則可通過s進行訪問在Java里都是通過引用來操縱對象的。 Java對象和引用的關(guān)系可以說是互相關(guān)聯(lián),卻又彼此獨立。彼此獨立主要表現(xiàn)在:引用是可以改變的,它可以指向別的對象,譬如上面的s,你可以給它另外的

8、對象,如:s = new StringBuffer(Java); 這樣一來,s就和它指向的第一個對象脫離關(guān)系。從存儲空間上來說,對象和引用也是獨立的,它們存儲在不同的地方,對象一般存儲在堆中,而引用存儲在速度更快的堆棧中。 引用可以指向不同的對象,對象也可以被多個引用操縱,如:StringBuffer s1 = s; 這條語句使得s1和s指向同一個對象。既然兩個引用指向同一個對象,那么不管使用哪個引用操縱對象,對象的內(nèi)容都發(fā)生改變,并且只有一份,通過s1和s得到的內(nèi)容自然也一樣,(String除外,因為String始終不變,String s1=”AAAA”; String s=s1,操作s,s

9、1由于始終不變,所以為s另外開辟了空間來存儲s,)如下面的程序: StringBuffer s; s = new StringBuffer(Java); StringBuffer s1 = s; s1.append( World); System.out.println(s1= + s1.toString();/打印結(jié)果為:s1=Java World System.out.println(s= + s.toString();/打印結(jié)果為:s=Java World 上面的程序表明,s1和s打印出來的內(nèi)容是一樣的,這樣的結(jié)果看起來讓人非常疑惑,但是仔細想想,s1和s只是兩個引用,它們只是操縱桿而已

10、,它們指向同一個對象,操縱的也是同一個對象,通過它們得到的是同一個對象的內(nèi)容。這就像汽車的剎車和油門,它們操縱的都是車速,假如汽車開始的速度是80,然后你踩了一次油門,汽車加速了,假如車速升到了120,然后你踩一下剎車,此時車速是從120開始下降的,假如下降到60,再踩一次油門,車速則從60開始上升,而不是從第一次踩油門后的120開始。也就是說車速同時受油門和剎車影響,它們的影響是累積起來的,而不是各自獨立(除非剎車和油門不在一輛車上)。所以,在上面的程序中,不管使用s1還是s操縱對象,它們對對象的影響也是累積起來的(更多的引用同理)。 只有理解了對象和引用的關(guān)系,才能理解參數(shù)傳遞。 一般面試

11、題中都會考Java傳參的問題,并且它的標準答案是Java只有一種參數(shù)傳遞方式:那就是按值傳遞,即Java中傳遞任何東西都是傳值。如果傳入方法的是基本類型的東西,你就得到此基本類型的一份拷貝。如果是傳遞引用,就得到引用的拷貝。 一般來說,對于基本類型的傳遞,我們很容易理解,而對于對象,總讓人感覺是按引用傳遞,看下面的程序:public class ObjectRef /基本類型的參數(shù)傳遞 public static void testBasicType(int m) System.out.println(m= + m);/m=50 m = 100; System.out.println(m= +

12、 m);/m=100 /參數(shù)為對象,不改變引用的值 ? public static void add(StringBuffer s) s.append(_add); /參數(shù)為對象,改變引用的值 ? public static void changeRef(StringBuffer s) s = new StringBuffer(Java); public static void main(String args) int i = 50; testBasicType(i); System.out.println(i);/i=50 StringBuffer sMain = new StringBu

13、ffer(init); System.out.println(sMain= + sMain.toString();/sMain=init add(sMain); System.out.println(sMain= + sMain.toString();/sMain=init_add changeRef(sMain); System.out.println(sMain= + sMain.toString();/sMain=init_add 以上程序的允許結(jié)果顯示出,testBasicType方法的參數(shù)是基本類型,盡管參數(shù)m的值發(fā)生改變,但并不影響i。 add方法的參數(shù)是一個對象,當把sMain傳

14、給參數(shù)s時,s得到的是sMain的拷貝,所以s和sMain指向同一個對象,因此,使用s操作影響的其實就是sMain指向的對象,故調(diào)用add方法后,sMain指向的對象的內(nèi)容發(fā)生了改變。 在changeRef方法中,參數(shù)也是對象,當把sMain傳給參數(shù)s時,s得到的是sMain的拷貝,但與add方法不同的是,在方法體內(nèi)改變了s指向的對象(也就是s指向了別的對象,牽著氣球的繩子換氣球了),給s重新賦值后,s與sMain已經(jīng)毫無關(guān)聯(lián),它和sMain指向了不同的對象,所以不管對s做什么操作,都不會影響sMain指向的對象,故調(diào)用changeRef方法前后sMain指向的對象內(nèi)容并未發(fā)生改變。 對于ad

15、d方法的調(diào)用結(jié)果,可能很多人會有這種感覺:這不明明是按引用傳遞嗎?對于這種問題,還是套用Bruce Eckel的話:這依賴于你如何看待引用,最終你會明白,這個爭論并沒那么重要。真正重要的是,你要理解,傳引用使得(調(diào)用者的)對象的修改變得不可預期。 public class Test public int I,j; public void test_m(Test a) Test b=new Test(); b.i=1; b.j=2; a=b; public void test_m1(Test a ) a.i = 1; a.j =2; public static void main(String argv) Test t=new Test(); t.i=5; t.j=6; System.out.println( t.i=+ t.

溫馨提示

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

評論

0/150

提交評論