2009-03-01 57 views
15

我一直在學習Java的幾個月,我現在開始學習C.在Java中傳遞引用和在C中傳遞指針有什麼區別?

我有點困惑,我的印象是,通過引用傳遞對象和指針傳遞到該對象是相同的事情:我認爲不同的是,在Java中,所有對象的傳遞都是自動完成指針的,在C中,實際上在這裏和那裏實際上要灑上星號和&符號。最近,在談話中,我確信有一個區別!

通過引用傳遞和傳遞指針有什麼區別?

回答

39

Java既不是Java 也不是 C具有傳遞引用。他們都嚴格按價值傳遞。

傳遞引用語義意味着當您更改方法中參數的值時,調用方將在參數中看到該更改。

現在,您可能會想:「但是在Java中就是這種情況!如果在方法中更改對象,調用者會看到這種變化。」 該對象不是參數。參數是只是該變量 - 如果您更改該變量的值,調用者將看不到。例如:

public void foo(Object x) 
{ 
    x = null; 
} 

public void caller() 
{ 
    Object y = new Object(); 
    foo(y); 
    // y is still not null! 
} 

如果該參數是真的按引用傳遞,y將是空之後。相反,y的值只是一個參考,並且該參考值是按值傳遞的。這是令人困惑的,因爲「參考」這個詞有兩種含義,但它們是不同的東西。

你可能想看看my article about C# parameter passing,看看什麼是可能的,如果Java的確實有傳遞引用語義,如C#做時(且僅當)您使用ref關鍵字。

您可能還想看看與該主題相關的評論my Stack Overflow answer

3

差異很微妙。在彙編級別,在這兩種情況下,對象的地址都被傳遞給函數。但是,在指針情況下,參數是一個獨立的指針,可用於修改目標對象(* pch ='x')或可用於訪問不同的對象(pch =「newstr」)。在參考案例中,該參數會自動指向目標對象。

1

如果你正在學習C(而不是C++),那麼就沒有參考。

C中的術語「通過引用傳遞」僅僅意味着你傳遞一個指針作爲存儲值的地址,以便該函數可以更改其值。 否則,您正在傳值,這意味着在堆棧上生成變量的副本,並且修改沒有影響。

在許多方面,這與您在Java中看到的類似,只不過在Java中您不必將事物明確地轉換爲指針或對其進行解引用。換句話說,當你傳遞一個指針時,地址被複制到堆棧中,所以如果你的函數改變指針(而不是指向它的數據),當你完成這個函數時,這些改變就會消失。同樣,當您在Java中傳遞對象引用時,可以更改對象的內容(例如,通過調用函數),但是如果將變量指向anothr對象,則離開後無效。

如果您使用C++(看起來像C),那麼您可以通過引用傳遞,在這種情況下,您不需要處理指針,並且對函數中變量的更改實際上直接更改外部值(除了你不能指向別的東西)。

+0

嘿,可以這樣說:「指針」是一種數據類型,「引用」只是一種處理數據的方式?一個是事物,另一個是技術? *我試圖避免在這裏使用「方法」的不明確性 – Ziggy 2009-03-01 22:33:25

+0

指針肯定是一種數據類型。然而,在C++(大多數C人最終使用)中,有一種稱爲參考的數據類型。這是一個問題,因爲在C++中實際上有兩種「通過引用傳遞」的方式,通過實際引用和通過指針。所以「通過參考」是一種方法。 – Uri 2009-03-01 23:14:55

2

有幾件事情

  • C沒有引用(儘管C++的)
  • Java沒有指針
  • 指針和引用的區別是,指針實際上是內存地址,你可以計算用。參考文獻不能被數值與
  • Java和C通計算(當傳遞在Java中的對象時,參考被複制到功能)
+0

我建議你從最後一個項目符號中刪除「默認」一詞 - C和Java按值傳遞,故事結束。 – 2009-03-01 22:32:30

2

相信一個指針是一個包含一個參考的變量。 隨着&你可以獲得一個內存方向(參考),並與*你可以訪問內存方向的內容。 我建議書The C programming Language

問候

1

Eric Lippert最近有一篇關於這方面的文章。他對C#編譯器的程序員,但無論他說,有有足夠的普遍性擴展到其他GC語言如Java:從文章

http://blogs.msdn.com/ericlippert/archive/2009/02/17/references-are-not-addresses.aspx

報價:

指針是嚴格比引用更「強大」;任何你可以用引用來做的事情,你可以用指針來做。 [...]

指針通常作爲地址來實現。地址是一個數字,它是「字節數組」的偏移量,即進程的整個虛擬地址空間。 [...]

由於所有這些原因,我們沒有在說明書中將引用描述爲地址。該規範只是說,引用類型的變量「存儲引用」給一個對象,並且對於如何實現這個對象而言完全模糊不清。同樣,一個指針變量存儲一個對象的「地址」,這個對象仍然很模糊。我們沒有任何地方說參考地址與地址相同。

所以,在C#中,引用是一些模糊的東西,可以讓你引用一個對象。除了解引用外,你不能對引用做任何事情,並將其與另一個引用進行比較以獲得相等性。而在C#中,一個指針被識別爲一個地址。

與引用相比,您可以使用包含地址的指針做更多的事情。地址可以通過數學操作;你可以從另一箇中減去一個,你可以爲它們添加整數,等等。他們的合法操作表明他們是「幻想號碼」,它們將索引到「陣列」中,即「虛擬地址空間」。

+0

這是在談論引用而不是「通過參考」 - 它們是相關但不同的概念。 – 2009-03-01 22:31:01

7

我認爲不同的是,在Java中,所有對象的傳遞都是用指針自動完成的,因爲在C中必須實際在這裏和那裏灑小星號和&符號。

概念,這是非常正確的。如果我們是迂腐的(這是一件好事),我們甚至可以說Java根本不會傳遞對象。傳遞的只是「指針」,在Java中被稱爲引用。所有間接都是自動完成的。所以,當你在C中使用「objref-> foo」而不是「objref.foo」,並且不能使用點因爲你使用了一個指針,所以在Java中你仍然可以使用這個點,因爲它不知道任何其他的無論如何,訪問成員。在C中,你可以傳遞指針(在這裏,它實際上叫做指針)你可以傳遞這個對象本身,在這種情況下傳遞一個副本。在C中,可以使用星號或「 - >」通過間接訪問指針指向的對象。在Java中,無論如何訪問對象的唯一方法是使用點(objref.member)。

如果我們再次迂迴(現在更重要),Java和C都沒有「通過引用」。我們在Java中傳遞的是指向對象的引用/指針,在C中,我們傳遞對象的副本(明顯的情況),或者我們再次傳遞指向對象的指針副本。所以在這兩種情況下 - Java和C - 我們傳遞的是對象的地址。不是在討論使用Java和C複製的原始Java類型 - 即使您也可以使用C語言傳遞它們的地址,集合類型(即結構)和C中的「原始類型」在中沒有區別那方面。

0

林不知道有關Java,但在C#或VB.net,你可以通過值或refrence

例如路過refrence

static void Main(string[] args) 
    { 
     int x = 1; 
     Foo(ref x); 
     Console.WriteLine(x.ToString());//this will print 2 
    } 

    private static void Foo(ref int x) 
    { 
     x++; 
    } 

通知傳遞的是x等於1,但是當你調用在Foo中x增加1時,方法Foo和x通過引用傳遞x原始值也增加

1

那些熟悉C/C++的讀者可能已經注意到對象引用出現 與指針類似。這種懷疑本質上是正確的。對象引用是 類似於內存指針。主要的區別 - 也是Java安全性的關鍵 - 您無法操作引用,因爲您可以使用實際的指針。因此,不能使對象引用指向任意的內存位置或像整數一樣操作它。

  • java不支持&運算符然後如何獲得java中的對象地址。
  • 在java中參考由對象例如)進行

MyClass的object1 =新MyClass的(;

MyClass object2 = object1;

即你可能認爲object1和object2引用單獨和不同的對象。 但是,這將是錯誤的。相反,在執行此片段後,object1和object2都將引用同一個對象。如果你改變其他任何一種效果。你可以在初始化後不改變對象的地址 即MyClass obj = new MyClass(); 作爲C++的參考,帶對象只能改變對象實例的值

注意:java提供了一個特殊的功能 object1被設置爲null,但object2仍然指向原始對象。

相關問題