日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

java 傳值 vs. 傳引用

 pstn 2007-11-22

java 傳值 vs. 傳引用

java程序的函數(shù)調(diào)用到底是傳值呢還是傳參呢?這可是個難纏的問題,如果搞不清楚還是挺容易出錯的:P對于這個問題,最經(jīng)典的解釋莫過于“java函數(shù)是傳值的,java函數(shù)傳遞的參數(shù)是對象的引用”
這兩句話好像初聽上去有點繞,不過意思倒是表達得蠻精確的。
我看到過幾個解釋這個問題的例子,不過個人感覺看過例子之后還是只知道是什么不知道為什么,停留在照貓畫虎的水平上還是挺容易出問題的。所以舉例子之前,先從jvm的實現(xiàn)原理上有個了解應當是不無裨益的。jvm的結構圖前一陣子貼到blog上了,那可是從“深入java虛擬機”這本巨牛的書上看來的,絕對有權威性。從jvm的結構圖上可以看出來,jvm在實現(xiàn)的時候將屬于它的內(nèi)存分為五部分,其中程序代碼(嚴格的說應當是字節(jié)碼)是放在java棧的棧幀中,而對象是從堆中分配的,堆這個東西我看可以理解成“對象池”。程序和程序中需要用到的對象放在兩個相對獨立的區(qū)域中,那么程序怎么使用對象呢?答案是程序中真正使用對象的地方其實只是聲明了一個對象的引用,也就是把堆中分配了的相應對象的地址放到引用中,棧和堆之間就是通過一個一個的引用來聯(lián)系的。引用嘛,我理解就是一個指針常量,指針常量又是個什么東西呢?說白了,就是一個無符號整數(shù),這個整數(shù)所表達的是引用對象的地址。好了,這下清楚了,不管是基本類型變量(int,float,double什么的)還是對象,相應的內(nèi)存地址中存放的都是一個數(shù)(無符號整數(shù),整數(shù),浮點數(shù)等)。傳遞參數(shù)的時候傳遞的就是相應內(nèi)存地址中的數(shù),所以說“java函數(shù)是傳值的”。當然,這個數(shù)對于基本類型和對象類型來說意義是不一樣的,對于基本類型這個數(shù)就是其值本身,傳遞值的結果就是,改變新的變量的值不影響舊的變量的值;而對于對象來說這個數(shù)是它的地址,傳遞這個值就相當于傳遞了真實對象的引用,傳遞了引用或者說是地址的結果就是變化會全局可見,所以又可以說“java函數(shù)傳遞的參數(shù)是對象的引用”。
唔,松口氣啦。經(jīng)過上面這一小堆討論,不難理解為什么java在傳遞參數(shù)時對于基本類型和對象表現(xiàn)不同:)
現(xiàn)在開始舉例了,舉網(wǎng)上搜來的例子,看看是不是比原來沒有上面的解釋的時候好理解一點?
public class TestRef
{
 public static void main(String[] args)
 {
  ValueObject vo1 = new ValueObject("A", 1);
  System.out.println("after vo1: " + vo1.getName()); //=A
 
  changeValue1(vo1);
  System.out.println("after changeValue1: " + vo1.getName());
                //=A1, changed
 
  changeValue2(vo1);
  System.out.println("after changeValue2: " + vo1.getName());
                //=A1, changeValue2內(nèi)部的賦值不會影響這里。
 }
 /**
  * 使用vo1自身的函數(shù)對其內(nèi)部數(shù)據(jù)進行改變是有效的,函數(shù)外可反映出來,
  * 因為這是對對象本身的操作
  * 這種object稱為可變的(mutable)
  * @param vo1
  */
 private static void changeValue1(ValueObject vo1)
 {
  vo1.setName("A1");
 }
 /**
  * 在函數(shù)內(nèi)給vo1重新賦值不會改變函數(shù)外的原始值,因為這種改變了引用的指向
  * @param vo1
  */
 private static void changeValue2(ValueObject vo1)
 {
  vo1 = new ValueObject("B", 2);
  System.out.println("inside changeValue2: "+ vo1.getName());
                //=B,賦值操作引起的結果變化僅在changeValue2內(nèi)部有效
 }
}
class ValueObject
{
 
 public ValueObject() {}
 
 public ValueObject(String name, int id)
 {
  this.name = name;
  this.id = id;
 }
 
 private String name;
 private int id;
 public int getId() {
  return id;
 }
 public void setId(int id) {
  this.id = id;
 }
 public String getName() {
  return name;
 }
 public void setName(String name) {
  this.name = name;
 }
}
java中對象的每個實例(就是對象)內(nèi)存地址是唯一的,它一旦被創(chuàng)建,能夠對這個地址進行操作的就是其本身,如果ValueObject類中沒有public void setName之類的方法對這個類的實例中的數(shù)據(jù)進行修改的話,程序是沒有任何別的方法可以修改ValueObject類的實例中的數(shù)據(jù),這個就是java的封裝特性。對于不提供修改內(nèi)部數(shù)據(jù)的方法的類,我們稱為不可變(immutable)的類。在函數(shù)中對傳入的參數(shù)變量進行賦值操作,只能在函數(shù)范圍內(nèi)改變局部變量指向的引用地址,但是不會改變原始地址的內(nèi)容。因此,在changeValue2(...)函數(shù)內(nèi)部的vo1和函數(shù)外的vo1雖然名字相同,但是實際上是不同的實例變量,只不過指向了和函數(shù)外的vo1同樣的地址,所以當我們用vo1=... 對其進行賦值的時候,只不過是把函數(shù)內(nèi)的臨時變量指向了新的地址,并沒有改變原始vo1內(nèi)存地址中的內(nèi)容。這就是在運行changeValue2(...)之后,vo1的值在main范圍內(nèi)仍然沒有被修改的原因。而changeValue1里面是調(diào)用的ValueObject本身的function來更改其內(nèi)容,因此是原始內(nèi)存地址中的數(shù)據(jù)被更改了,所以是全局有效的.
總結:
對于引用類型的傳參也是傳值的,傳的是引用類型的值,其實就是對象的地址。
1. java參數(shù)傳遞值的。
2. java所有對像變量都是對像的引用。
不知道我解釋清楚沒,要是還是不能理解java參數(shù)傳遞的原理,強烈推薦看看“深入java虛擬機”一書的第五章,中文翻譯的不是特別出色,可以看看英文原版,應該比中文版好懂:)

    本站是提供個人知識管理的網(wǎng)絡存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊一鍵舉報。
    轉藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多