Bunu kapsayan harika cevaplar zaten var. Ben c ++ referans Pass-by-value Java ile davranışları zıt çok basit bir örnek (bu derleme) paylaşarak küçük bir katkı yapmak istedim .
Birkaç nokta:
- "Referans" terimi, iki ayrı anlama sahip aşırı yüklenmedir. Java'da basitçe bir işaretçi anlamına gelir, ancak "Referansla" bağlamında, içeri aktarılan orijinal değişken için bir tanıtıcı anlamına gelir.
- Java, değere göre . Java (diğer diller arasında) C'nin soyundan gelir. C'den önce, FORTRAN ve COBOL gibi birkaç (ancak hepsi değil) önceki dil PBR'yi destekledi, ancak C desteklemedi. PBR bu diğer dillerin alt rutinler içinde geçirilen değişkenlerde değişiklik yapmasına izin verdi. Aynı şeyi başarmak için (yani fonksiyonların içindeki değişkenlerin değerlerini değiştirmek için), C programcıları değişkenlere fonksiyonlara yöneltti. Java gibi C'den esinlenen diller bu fikri ödünç aldı ve Java'nın işaretçileri Referanslar olarak adlandırması dışında C'nin yaptığı yöntemlere işaretçi aktarmaya devam ediyor. Yine, bu "Referans" kelimesinin "Referansla Geçiş" ten farklı bir kullanımıdır.
- C ++ başvuruya izin verir , "&" karakterini (hem C hem de C ++ 'da "bir değişkenin adresini" belirtmek için kullanılan karakterle aynı olan) bir referans parametresi bildirerek . Örneğin, bir işaretçiyi başvuru ile iletirsek, parametre ve bağımsız değişken yalnızca aynı nesneyi işaret etmez. Aksine, bunlar aynı değişkendir. Biri farklı bir adrese veya null değerine ayarlanırsa diğeri de ayarlanır.
- Aşağıdaki C ++ örneğinde , başvuru ile boş bir sonlandırılmış dizeye bir işaretçi geçiriyorum . Ve aşağıdaki Java örneğinde, bir String'e bir Java başvurusu geçiriyorum (yine, bir String'e gösterici ile aynı) değere göre. Yorumlarda çıktıya dikkat edin.
Referans örneğiyle C ++ geçişi:
using namespace std;
#include <iostream>
void change (char *&str){ // the '&' makes this a reference parameter
str = NULL;
}
int main()
{
char *str = "not Null";
change(str);
cout<<"str is " << str; // ==>str is <null>
}
Java, örnek örneği ile "bir Java başvurusu" iletir
public class ValueDemo{
public void change (String str){
str = null;
}
public static void main(String []args){
ValueDemo vd = new ValueDemo();
String str = "not null";
vd.change(str);
System.out.println("str is " + str); // ==> str is not null!!
// Note that if "str" was
// passed-by-reference, it
// WOULD BE NULL after the
// call to change().
}
}
DÜZENLE
Birkaç kişi ya benim örneklerime bakmıyor ya da c ++ örneğini alamadıklarını gösteren yorumlar yazdı. Bağlantıyı kesmenin nerede olduğundan emin değilim, ancak c ++ örneğini tahmin etmek net değil. Aynı örneği pascal'da gönderiyorum çünkü pass-by-referansın pascal'da daha temiz göründüğünü düşünüyorum, ama yanlış olabilirim. İnsanları daha çok karıştırıyorum; Umarım değildir.
Pascal'de, referansla iletilen parametrelere "var parametreleri" denir. Aşağıdaki setToNil prosedüründe, lütfen 'ptr' parametresinden önce gelen 'var' anahtar kelimesine dikkat edin. Bu yordama bir işaretçi iletildiğinde , başvuru ile iletilir . Davranışı not edin: Bu yordam ptr değerini nil olarak ayarladığında (bu NULL için parola konuşur), argümanı nil olarak ayarlar - Java'da bunu yapamazsınız.
program passByRefDemo;
type
iptr = ^integer;
var
ptr: iptr;
procedure setToNil(var ptr : iptr);
begin
ptr := nil;
end;
begin
new(ptr);
ptr^ := 10;
setToNil(ptr);
if (ptr = nil) then
writeln('ptr seems to be nil'); { ptr should be nil, so this line will run. }
end.
DÜZENLEME 2
Ken Arnold, James Gosling (Java'yı icat eden kişi) ve David Holmes, bölüm 2, bölüm 2.6.5 tarafından yazılan "THE Java Programlama Dili" nden bazı alıntılar
Yöntemlere ilişkin tüm parametreler "değere göre" geçirilir . Başka bir deyişle, bir yöntemdeki parametre değişkenlerinin değerleri, invoker'ın argüman olarak belirtilen kopyalarıdır.
Nesneler için de aynı noktayı vurgulamaya devam ediyor. . .
Parametre bir nesne başvurusu olduğunda, nesnenin kendisi değil, nesnenin başvurusu olduğunu ve "değere göre" iletildiğini unutmayın .
Ve aynı bölümün sonuna doğru, java'nın sadece değere göre geçtiği ve asla referansla geçmediği konusunda daha geniş bir açıklama yapar.
Java programlama dili nesneleri referans olarak iletmez; bu
değer nesne referansları geçer . Aynı başvurunun iki kopyası aynı gerçek nesneyi ifade ettiğinden, bir referans değişkeni üzerinden yapılan değişiklikler diğeri tarafından görülebilir. Tam olarak bir parametre geçirme modu vardır - değer -ve ile işleri basit tutmaya yardımcı olur.
Kitabın bu bölümünde Java'da parametre geçişi ve referans by-pass ve by-value arasındaki farkın büyük bir açıklaması vardır ve Java'nın yaratıcısıdır. Özellikle ikna olmadıysanız, kimseyi okumaya teşvik ederim.
Bence iki model arasındaki fark çok incedir ve gerçekten referans olarak kullandığınız yerde programlama yapmadıysanız, iki modelin farklı olduğu yerleri kaçırmak kolaydır.
Umarım bu tartışmayı çözer, ama muhtemelen çözmez.
DÜZENLE 3
Bu yazıya biraz takıntılı olabilirim. Muhtemelen Java üreticilerinin yanlışlıkla yanlış bilgi yaydığını hissediyorum. İşaretçiler için "referans" kelimesini kullanmak yerine, başka bir şey kullandılarsa, dingleberry diyelim, sorun olmazdı. "Java, pislikleri referans ile değil değere geçirir" diyebilirsiniz ve kimse karışmaz.
Bu nedenle sadece Java geliştiricilerinin sorunu var. "Referans" kelimesine bakarlar ve bunun tam olarak ne anlama geldiğini bildiklerini düşünürler, bu yüzden karşıt argümanı düşünmek bile zahmetine girmezler.
Her neyse, eski bir gönderide, gerçekten sevdiğim bir balon benzetmesi yapan bir yorum fark ettim. Öyle ki, noktayı göstermek için bir dizi karikatür yapmak için bazı küçük resimleri yapıştırmaya karar verdim.
Bir referansın değere göre iletilmesi - Referanstaki değişiklikler, arayanın kapsamına yansıtılmaz, ancak nesnedeki değişiklikler yapılır. Bunun nedeni, başvurunun kopyalanmasıdır, ancak hem orijinal hem de kopya aynı nesneye başvurur.
Referansla geç - Referansın bir kopyası yok. Tek referans hem arayan hem de çağrılan işlev tarafından paylaşılır. Referans veya Nesne verilerindeki herhangi bir değişiklik, arayanın kapsamına yansıtılır.
DÜZENLEME 4
Bu konuda, Java'da parametre geçişinin düşük düzeyli uygulamasını açıklayan yayınlar gördüm, bu da büyük ve çok yararlı olduğunu düşünüyorum çünkü soyut bir fikri somutlaştırıyor. Ancak, bana göre soru daha çok davranışın teknik uygulamasından çok dil spesifikasyonunda tarif edilen davranış hakkındadır. Bu, Java Dil Spesifikasyonu, bölüm 8.4.1'den alınmıştır :
Yöntem veya kurucu çağrıldığında (§15.12), gerçek argüman ifadelerinin değerleri , yöntemin veya kurucunun gövdesinin yürütülmesinden önce, her biri bildirilen türden yeni oluşturulan parametre değişkenlerini başlatır. DeclaratorId'de görünen Tanımlayıcı, resmi parametreye başvurmak için yöntem veya yapıcı gövdesinde basit bir ad olarak kullanılabilir.
Yani java, bir yöntemi uygulamadan önce iletilen parametrelerin bir kopyasını oluşturur. Üniversitede derleyici okuyan çoğu insan gibi ben de "Ejderha Kitabı" nı kullandım olduğunu derleyiciler kitabı. Bölüm 1'de "Değer değerine göre çağrı" ve "Referansa göre çağrı" ile ilgili iyi bir açıklamaya sahiptir. Değere göre çağrı açıklaması, Java Spesifikasyonları ile tam olarak eşleşir.
90'lı yıllarda derleyiciler okuduğumda, 1986'dan itibaren Java'yı yaklaşık 9 veya 10 yıl öncesine dayanan kitabın ilk baskısını kullandım. Ancak, 2007'den 2. Baskı'nın bir kopyasına rastladım aslında Java'dan bahseden ! "Parametre Geçiş Mekanizmaları" etiketli Bölüm 1.6.6, parametre geçişini oldukça iyi açıklamaktadır. Java'dan bahseden "Değere göre çağrı" başlığı altında bir alıntı:
Call-by-value'da, gerçek parametre değerlendirilir (eğer bir ifade ise) veya kopyalanır (bir değişkense). Değer, çağrılan prosedürün karşılık gelen resmi parametresine ait konuma yerleştirilir. Bu yöntem C ve Java'da kullanılır ve C ++ 'da ve diğer birçok dilde yaygın bir seçenektir.