李 冉,陳蘭芹
(荊楚理工學(xué)院 計(jì)算機(jī)工程學(xué)院,湖北 荊門448000)
Java語(yǔ)言中,參數(shù)傳遞機(jī)制對(duì)于初學(xué)者來(lái)說(shuō),一直是一個(gè)難點(diǎn),也是一個(gè)重點(diǎn)。關(guān)于這方面的教材、論文和參考手冊(cè)很多,但是說(shuō)法不一,有的模糊帶過(guò)。比如,有的認(rèn)為Java的參數(shù)傳遞分兩種情況,即值傳遞和引用傳遞;有的認(rèn)為Java中所有的參數(shù)傳遞都是按值傳遞。其實(shí)這些說(shuō)法都有一定的合理性,但是沒(méi)有清晰地說(shuō)明它的基本原理,容易讓初學(xué)者陷入邏輯漩渦。本文參閱了各種說(shuō)法,并結(jié)合了JDK的幫助文檔,首先從Java的變量?jī)?nèi)存分配機(jī)制開始,全面深入地剖析Java語(yǔ)言中參數(shù)傳遞機(jī)制,并得出最合理的結(jié)論。
Java的內(nèi)存分配機(jī)制很復(fù)雜,這里只分析Java的變量?jī)?nèi)存分配規(guī)則,以助于理解Java的參數(shù)傳遞機(jī)制,而不考慮它在堆區(qū)、棧區(qū)還是靜態(tài)數(shù)據(jù)區(qū),也不考慮生命周期。
Java的數(shù)據(jù)類型分為兩大類,分別是基本數(shù)據(jù)類型和引用數(shù)據(jù)類型[1]?;緮?shù)據(jù)類型,也稱為簡(jiǎn)單數(shù)據(jù)類型,包括byte、char、short、int、long、float、double和boolean共8種;引用數(shù)據(jù)類型也稱為復(fù)雜數(shù)據(jù)類型,包括接口、類和數(shù)組共3種。
JVM根據(jù)變量的數(shù)據(jù)類型來(lái)分配內(nèi)存空間,Java中不同大類型的變量?jī)?nèi)存分配規(guī)則不同。
1)對(duì)于基本數(shù)據(jù)類型
JVM對(duì)于基本數(shù)據(jù)類型的變量,只分配一定大小的內(nèi)存單元,用于存儲(chǔ)該變量的值。如果復(fù)制該變量,則是復(fù)制該內(nèi)存單元的值,例如:
double x=7.3;//定義了雙精度類型變量x,并賦初值為7.3
double y=x;//定義了雙精度類型變量y,并copy了x的值
對(duì)應(yīng)的內(nèi)存單元示意圖見(jiàn)圖1。
圖1 基本數(shù)據(jù)類型變量?jī)?nèi)存分配圖
x變量的值復(fù)制給了y變量,此時(shí),x、y是兩個(gè)值相同的但是完全獨(dú)立的兩個(gè)內(nèi)存單元。
2)對(duì)于引用數(shù)據(jù)類型
JVM對(duì)于引用數(shù)據(jù)類型的變量,也是分配一定大小的內(nèi)存單元,用于存儲(chǔ)該變量所指向的對(duì)象,該變量的值為對(duì)象的引用。如果復(fù)制該變量,實(shí)際上是復(fù)制了該變量?jī)?nèi)存單元的值,而不是復(fù)制它所指的對(duì)象的值,例如:
Point p1=new Point(23,34);//Point為Java中一個(gè)已有的類
Point p2=p1;//將p1的值復(fù)制給了p2變量對(duì)應(yīng)的內(nèi)存單元示意圖見(jiàn)圖2。
圖2 引用數(shù)據(jù)類型變量?jī)?nèi)存分配圖
p1變量的值復(fù)制給了p2變量,此時(shí)p1與p2存放的值是同一個(gè)對(duì)象的引用,即指向同一個(gè)對(duì)象,但是它們是兩個(gè)完全獨(dú)立的內(nèi)存單元。
對(duì)于p1和它所指向的對(duì)象,本質(zhì)上也是兩個(gè)完全不同的內(nèi)存單元。
在Java語(yǔ)言中,參數(shù)傳遞是在程序運(yùn)行過(guò)程中,實(shí)際參數(shù)將參數(shù)值傳遞給被調(diào)用的方法中相應(yīng)的形式參數(shù),然后實(shí)現(xiàn)對(duì)數(shù)據(jù)處理,或者完成特定的功能。實(shí)際參數(shù)是調(diào)用過(guò)程中,從主調(diào)方法傳遞給被調(diào)用方法的值,它可以是常量、變量或者表達(dá)式;形式參數(shù)是被調(diào)用方法用于接收并存儲(chǔ)實(shí)際參數(shù)值的變量[2]。
Java語(yǔ)言中,參數(shù)傳遞的機(jī)制只有一個(gè),即將實(shí)際參數(shù)的值復(fù)制一份賦值給形式參數(shù),形式參數(shù)值的任何變化,不會(huì)影響到實(shí)參的值。實(shí)際參數(shù)可以是常量、變量或者表達(dá)式,變量又有很多種類型,但是都遵循這個(gè)機(jī)制。
Java語(yǔ)言中,常量和表達(dá)式都有值的屬性,在參數(shù)傳遞中,將常量的值或者表達(dá)式計(jì)算的值復(fù)制一份賦值給形式參數(shù)。在方法內(nèi)部,形式參數(shù)的值發(fā)生任何改變,不會(huì)影響到實(shí)際參數(shù)的值。實(shí)際上,常量和表達(dá)式的值不允許修改,也不可能修改。
實(shí)際參數(shù)為基本類型變量時(shí),參數(shù)傳遞過(guò)程中,將實(shí)參變量的值復(fù)制一份賦值給形式參數(shù)。實(shí)參變量和形參變量是兩個(gè)獨(dú)立的內(nèi)存單元,形參變量的值發(fā)生任何變化,不會(huì)影響到實(shí)參變量的值,如下例程很好地驗(yàn)證這種傳遞邏輯關(guān)系。
運(yùn)行結(jié)果如下:
在fun方法中,形參d的初始值,d=12.3
在fun方法中,形參d的初始值,d=15.3
在main方法中,實(shí)參f在fun方法執(zhí)行之后的值,f=12.3
執(zhí)行過(guò)程如圖3所示。
圖3 實(shí)參為簡(jiǎn)單類型變量的參數(shù)傳遞執(zhí)行過(guò)程示意圖
實(shí)際參數(shù)為引用類型變量時(shí),參數(shù)傳遞不是實(shí)參變量所指向的對(duì)象的值,而是實(shí)參變量本身的值,即所指對(duì)象的引用。傳遞的實(shí)現(xiàn)就是將實(shí)參變量所存儲(chǔ)的引用的值復(fù)制一份賦值給形參變量,形參變量的內(nèi)存單元也存儲(chǔ)了該對(duì)象的引用值。但是形參變量與實(shí)參變量是兩個(gè)獨(dú)立的存儲(chǔ)單元,形參變量?jī)?nèi)存單元值的變化不會(huì)影響到實(shí)參變量。如下例程很好地驗(yàn)證了這種邏輯關(guān)系。
運(yùn)行結(jié)果如下:
圖4 實(shí)參為引用類型變量的參數(shù)傳遞執(zhí)行過(guò)程示意圖
由圖3和圖4可以看出,引用類型實(shí)參到形參的參數(shù)傳遞,與簡(jiǎn)單類型實(shí)參到形參的傳遞方式一樣,都是值的復(fù)制,只不過(guò)被復(fù)制的值的含義不同而已。
在Java語(yǔ)言中,參數(shù)傳遞的機(jī)制本質(zhì)上就是值的復(fù)制,即只是從實(shí)際參數(shù)到形式參數(shù)變量的值的復(fù)制。也可以說(shuō),在Java中,參數(shù)傳遞都是按值傳遞的,就像快遞公司送包裹一樣,不關(guān)心包裹的內(nèi)容是什么。一些文章或者書籍中,將參數(shù)傳遞分為按值傳遞和按引用傳遞,是考慮了參數(shù)值的意義,這與Java參數(shù)傳遞的實(shí)現(xiàn)機(jī)制是沒(méi)有關(guān)系的。初學(xué)者只要搞清楚了Java中變量類型分類和內(nèi)存分配機(jī)制,就能靈活地使用參數(shù)傳遞機(jī)制。
[1]??藸?Java編程思想[M].陳昊鵬,譯.4版.北京:機(jī)械工業(yè)出版社,2007.
[2]昊斯特曼.Java核心技術(shù):卷I[M].葉乃文,鄺勁筠,杜永萍,譯.北京:機(jī)械工業(yè)出版社,2008.