Sudah ada jawaban bagus yang membahas hal ini. Saya ingin membuat kontribusi kecil dengan membagikan contoh yang sangat sederhana (yang akan mengkompilasi) yang membedakan perilaku antara Pass-by-reference dalam c ++ dan Pass-by-value di Jawa.
Beberapa poin:
- Istilah "referensi" adalah kelebihan beban dengan dua makna yang terpisah. Di Jawa itu hanya berarti pointer, tetapi dalam konteks "Pass-by-reference" itu berarti pegangan ke variabel asli yang diteruskan.
- Java adalah Pass-by-value . Java adalah turunan dari C (di antara bahasa-bahasa lain). Sebelum C, beberapa (tetapi tidak semua) bahasa sebelumnya seperti FORTRAN dan COBOL mendukung PBR, tetapi C tidak. PBR memungkinkan bahasa-bahasa lain ini untuk membuat perubahan pada variabel yang dikirimkan di dalam sub-rutin. Untuk mencapai hal yang sama (yaitu mengubah nilai variabel di dalam fungsi), programmer C meneruskan pointer ke variabel menjadi fungsi. Bahasa yang terinspirasi oleh C, seperti Java, meminjam ide ini dan terus meneruskan pointer ke metode seperti yang dilakukan C, kecuali bahwa Java menyebut pointer-pointernya Referensi. Sekali lagi, ini adalah penggunaan kata "Referensi" yang berbeda dari pada "Pass-By-Reference".
- C ++ memungkinkan Pass-by-reference dengan mendeklarasikan parameter referensi menggunakan karakter "&" (yang kebetulan merupakan karakter yang sama dengan yang digunakan untuk menunjukkan "alamat variabel" di C dan C ++). Sebagai contoh, jika kita meneruskan sebuah pointer dengan referensi, parameter dan argumennya tidak hanya menunjuk ke objek yang sama. Sebaliknya, mereka adalah variabel yang sama. Jika satu diatur ke alamat yang berbeda atau ke nol, begitu pula yang lainnya.
- Dalam contoh C ++ di bawah ini saya meneruskan sebuah pointer ke string yang diakhiri dengan referensi . Dan dalam contoh Java di bawah ini saya meneruskan referensi Java ke sebuah String (sekali lagi, sama dengan pointer ke sebuah String) dengan nilai. Perhatikan output dalam komentar.
C ++ lulus dengan contoh referensi:
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 meneruskan "referensi Java" dengan contoh nilai
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().
}
}
EDIT
Beberapa orang menulis komentar yang sepertinya mengindikasikan bahwa mereka tidak melihat contoh saya atau mereka tidak mendapatkan contoh c ++. Tidak yakin di mana putuskan, tetapi menebak contoh c ++ tidak jelas. Saya memposting contoh yang sama dalam pascal karena saya pikir pass-by-reference terlihat lebih bersih dalam pascal, tetapi saya bisa saja salah. Saya mungkin lebih membingungkan orang; Saya harap tidak.
Dalam pascal, parameter yang diteruskan oleh referensi disebut "parameter var". Dalam prosedur setToNil di bawah ini, harap perhatikan kata kunci 'var' yang mendahului parameter 'ptr'. Ketika sebuah pointer diteruskan ke prosedur ini, itu akan diteruskan dengan referensi . Perhatikan tingkah lakunya: ketika prosedur ini menyetel ptr ke nil (itu berbicara pascal untuk NULL), itu akan menetapkan argumen ke nil - Anda tidak dapat melakukannya di Jawa.
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.
EDIT 2
Beberapa kutipan dari "THE Java Programming Language" oleh Ken Arnold, James Gosling (orang yang menemukan Java) , dan David Holmes, bab 2, bagian 2.6.5
Semua parameter ke metode diteruskan "berdasarkan nilai" . Dengan kata lain, nilai-nilai variabel parameter dalam suatu metode adalah salinan dari invoker yang ditentukan sebagai argumen.
Dia melanjutkan untuk membuat titik yang sama tentang benda. . .
Anda harus mencatat bahwa ketika parameter adalah referensi objek, itu adalah referensi objek-bukan objek itu sendiri-yang dilewatkan "oleh nilai" .
Dan menjelang akhir bagian yang sama ia membuat pernyataan yang lebih luas tentang java yang hanya lewat nilai dan tidak pernah lewat referensi.
Bahasa pemrograman Java tidak melewatkan objek dengan referensi; itu
melewati referensi objek dengan nilai . Karena dua salinan dari referensi yang sama merujuk ke objek aktual yang sama, perubahan yang dilakukan melalui satu variabel referensi dapat dilihat melalui yang lainnya. Tepat ada satu parameter mode lewat- lulus dengan nilai -dan yang membantu menjaga hal-hal sederhana.
Bagian buku ini memiliki penjelasan yang bagus tentang parameter yang lewat di Jawa dan perbedaan antara pass-by-reference dan pass-by-value dan oleh pencipta Java. Saya akan mendorong siapa pun untuk membacanya, terutama jika Anda masih tidak yakin.
Saya pikir perbedaan antara kedua model sangat halus dan kecuali Anda telah melakukan pemrograman di mana Anda benar-benar menggunakan pass-by-reference, mudah untuk kehilangan di mana dua model berbeda.
Saya harap ini menyelesaikan perdebatan, tapi mungkin tidak.
EDIT 3
Saya mungkin sedikit terobsesi dengan posting ini. Mungkin karena saya merasa bahwa pembuat Java secara tidak sengaja menyebarkan informasi yang salah. Jika alih-alih menggunakan kata "referensi" untuk petunjuk yang mereka gunakan sesuatu yang lain, katakanlah dingleberry, tidak akan ada masalah. Anda bisa mengatakan, "Java melewati dingleberry dengan nilai dan bukan dengan referensi", dan tidak ada yang akan bingung.
Itulah alasan mengapa hanya pengembang Java yang bermasalah dengan ini. Mereka melihat kata "referensi" dan berpikir mereka tahu persis apa artinya itu, sehingga mereka bahkan tidak repot-repot mempertimbangkan argumen yang berlawanan.
Ngomong-ngomong, saya perhatikan komentar di posting lama, yang membuat analogi balon yang sangat saya sukai. Sedemikian rupa sehingga saya memutuskan untuk merekatkan beberapa clip-art untuk membuat satu set kartun untuk menggambarkan intinya.
Melewati referensi dengan nilai - Perubahan ke referensi tidak tercermin dalam ruang lingkup pemanggil, tetapi perubahan pada objek. Ini karena referensi disalin, tetapi yang asli dan salinan merujuk ke objek yang sama.
Lulus dengan referensi - Tidak ada salinan referensi. Referensi tunggal dibagikan oleh penelepon dan fungsi yang dipanggil. Setiap perubahan pada referensi atau data Objek tercermin dalam ruang lingkup pemanggil.
EDIT 4
Saya telah melihat posting pada topik ini yang menggambarkan implementasi level rendah dari passing parameter di Jawa, yang menurut saya hebat dan sangat membantu karena membuat ide abstrak menjadi konkret. Namun, bagi saya pertanyaannya lebih tentang perilaku yang dijelaskan dalam spesifikasi bahasa daripada tentang implementasi teknis dari perilaku tersebut. Ini adalah kutipan dari Spesifikasi Bahasa Jawa, bagian 8.4.1 :
Ketika metode atau konstruktor dipanggil (§15.12), nilai-nilai dari ekspresi argumen aktual menginisialisasi variabel parameter yang baru dibuat, masing-masing dari tipe yang dideklarasikan, sebelum eksekusi badan metode atau konstruktor. Identifier yang muncul di DeclaratorId dapat digunakan sebagai nama sederhana di tubuh metode atau konstruktor untuk merujuk ke parameter formal.
Yang berarti, java membuat salinan dari parameter yang diteruskan sebelum menjalankan suatu metode. Seperti kebanyakan orang yang belajar compiler di perguruan tinggi, saya menggunakan "The Dragon Buku" yang merupakan THE kompiler buku. Ini memiliki deskripsi yang baik tentang "Nilai-panggilan-" dan "Referensi-berdasarkan-panggilan" di Bab 1. Deskripsi panggilan-menurut-nilai cocok dengan Java Specs dengan tepat.
Kembali ketika saya mempelajari kompiler-di 90-an, saya menggunakan edisi pertama buku dari tahun 1986 yang pra-tanggal Jawa sekitar 9 atau 10 tahun. Namun, saya hanya menemukan salinan Edisi ke - 2 dari tahun 2007 yang sebenarnya menyebutkan Java! Bagian 1.6.6 yang berlabel "Mekanisme Passing Parameter" menggambarkan parameter yang lewat dengan cukup baik. Berikut adalah kutipan di bawah judul "Call-by-value" yang menyebutkan Java:
Dalam panggilan-oleh-nilai, parameter aktual dievaluasi (jika itu ekspresi) atau disalin (jika itu adalah variabel). Nilai ditempatkan di lokasi milik parameter formal yang sesuai dari prosedur yang disebut. Metode ini digunakan dalam bahasa C dan Java, dan merupakan pilihan umum dalam bahasa C ++, dan juga di sebagian besar bahasa lainnya.