Dalam C ++ argumen referensi ke fungsi memungkinkan fungsi untuk membuat referensi merujuk ke sesuatu yang lain:
int replacement = 23;
void changeNumberReference(int& reference) {
reference = replacement;
}
int main() {
int i = 1;
std::cout << "i=" << i << "\n"; // i = 1;
changeNumberReference(i);
std::cout << "i=" << i << "\n"; // i = 23;
}
Secara analogi, argumen referensi konstan ke suatu fungsi akan menimbulkan kesalahan waktu kompilasi jika kami mencoba mengubah referensi:
void changeNumberReference(const int& reference) {
reference = replacement; // compile-time error: assignment of read-only reference 'reference'
}
Sekarang, dengan Java, dokumen mengatakan bahwa argumen fungsi tipe non-primitif adalah referensi. Contoh dari dokumen resmi:
public void moveCircle(Circle circle, int deltaX, int deltaY) {
// code to move origin of circle to x+deltaX, y+deltaY
circle.setX(circle.getX() + deltaX);
circle.setY(circle.getY() + deltaY);
// code to assign a new reference to circle
circle = new Circle(0, 0);
}
Kemudian lingkaran diberi referensi ke objek Lingkaran baru dengan x = y = 0. Penugasan ulang ini tidak memiliki permanen, karena referensi dilewatkan oleh nilai dan tidak dapat berubah.
Bagi saya ini sama sekali tidak seperti referensi C ++. Itu tidak menyerupai referensi C ++ biasa karena Anda tidak dapat membuatnya merujuk ke sesuatu yang lain, dan itu tidak menyerupai referensi C ++ const karena di Jawa, kode yang akan berubah (tetapi sebenarnya tidak) referensi tidak membuang kompilasi kesalahan waktu
Ini lebih mirip dalam perilaku dengan pointer C ++. Anda bisa menggunakannya untuk mengubah nilai objek runcing, tetapi Anda tidak bisa mengubah nilai pointer itu sendiri dalam suatu fungsi. Juga, seperti dengan pointer C ++ (tetapi tidak dengan referensi C ++), di Java Anda bisa memberikan "null" sebagai nilai untuk argumen seperti itu.
Jadi pertanyaan saya adalah: Mengapa Java menggunakan gagasan "referensi"? Apakah harus dipahami bahwa mereka tidak menyerupai referensi C ++? Atau apakah mereka memang sangat mirip dengan referensi C ++ dan saya kehilangan sesuatu?
Jawaban:
Mengapa? Karena, meskipun terminologi yang konsisten umumnya baik untuk keseluruhan profesi, perancang bahasa tidak selalu menghargai penggunaan bahasa perancang bahasa lain, terutama jika bahasa lain itu dianggap sebagai pesaing.
Tapi sungguh, tidak menggunakan 'referensi' adalah pilihan yang sangat baik. "Referensi" dalam C ++ hanyalah sebuah konstruksi bahasa untuk memperkenalkan alias (nama alternatif untuk entitas yang persis sama) secara eksplisit. Hal-hal akan jauh lebih jelas dari mereka hanya menyebut fitur baru "alias" di tempat pertama. Namun, pada saat itu kesulitan terbesarnya adalah membuat semua orang memahami perbedaan antara pointer (yang memerlukan dereferencing) dan referensi (yang tidak), jadi yang penting itu disebut sesuatu selain "penunjuk", dan tidak begitu khususnya istilah apa yang digunakan.
Java tidak memiliki pointer, dan bangga karenanya, jadi menggunakan "pointer" sebagai sebuah istilah bukanlah pilihan. Namun, "referensi" yang berperilaku cukup sedikit seperti pointer C ++ lakukan ketika Anda menyebarkannya - perbedaan besar adalah bahwa Anda tidak dapat melakukan operasi tingkat rendah yang lebih jahat (casting, menambahkan ...) pada mereka , tetapi mereka menghasilkan semantik yang sama persis ketika Anda menyerahkan gagang ke entitas yang identik vs entitas yang kebetulan sama. Sayangnya, istilah "penunjuk" membawa begitu banyak asosiasi tingkat rendah yang negatif sehingga tidak mungkin diterima oleh masyarakat Jawa.
Hasilnya adalah bahwa kedua bahasa menggunakan istilah samar yang sama untuk dua hal yang agak berbeda, keduanya dapat mengambil untung dari nama yang lebih spesifik, tetapi keduanya tidak akan diganti dalam waktu dekat. Bahasa alami juga terkadang membuat frustasi!
sumber
NullPointerException
dengan fakta bahwa JLS menggunakan istilah "pointer"?NullPointerException
bukan penunjuk, tetapi merupakan pengecualian yang menunjukkan bahwa, pada tingkat yang lebih rendah, penunjuk NULL diteruskan / ditinjau ulang. MenggunakanPointer
sebagai bagian dari pengecualian, jika ada, menambah gambar buruk yang mereka miliki. JLS harus menyebutkan pointer, karena VM Java terutama ditulis dalam bahasa yang menggunakannya. Anda tidak dapat mendeskripsikan spesifikasi bahasa secara akurat tanpa menjelaskan cara kerja internalReferensi adalah hal yang mengacu pada hal lain. Berbagai bahasa telah memberikan makna yang lebih spesifik pada kata "referensi", biasanya untuk "sesuatu seperti pointer tanpa semua aspek buruk". C ++ menganggap makna tertentu, seperti halnya Java atau Perl.
Dalam C ++, referensi lebih seperti alias (yang dapat diimplementasikan melalui pointer). Ini memungkinkan lewat referensi atau keluar argumen .
Di Jawa, referensi adalah petunjuk kecuali bahwa ini bukan konsep bahasa yang ditegaskan: Semua objek adalah referensi, tipe primitif seperti angka tidak. Mereka tidak ingin mengatakan "pointer" karena tidak ada aritmatika pointer dan tidak ada pointer reified di Jawa, tetapi mereka ingin menjelaskan bahwa ketika Anda memberikan
Object
argumen, objek tidak disalin . Ini juga bukan lewat referensi , tetapi sesuatu yang lebih seperti lulus dengan berbagi .sumber
Sebagian besar kembali ke Algol 68, dan sebagian ke reaksi terhadap cara C mendefinisikan pointer.
Algol 68 mendefinisikan konsep yang disebut referensi. Itu hampir sama dengan (misalnya) pointer di Pascal. Itu adalah sel yang berisi NIL atau alamat beberapa sel lain dari beberapa jenis tertentu. Anda dapat menetapkan referensi, sehingga referensi dapat merujuk ke satu sel pada satu waktu, dan sel yang berbeda setelah dipindahkan. Namun, itu tidak mendukung apa pun yang analog dengan aritmetika pointer C atau C ++.
Paling tidak sebagaimana Algol 68 mendefinisikan hal-hal, bagaimanapun, referensi adalah konsep yang cukup bersih yang cukup canggung untuk digunakan dalam praktik. Sebagian besar definisi variabel sebenarnya dari referensi, sehingga mereka mendefinisikan notasi steno untuk mencegahnya menjadi benar-benar lepas kendali, tetapi lebih dari penggunaan sepele bisa menjadi canggung dengan cukup cepat pula.
Misalnya, deklarasi suka
INT j := 7;
benar-benar diperlakukan oleh kompilator sebagai deklarasi sukaREF INT j = NEW LOC INT := 7
. Jadi, apa yang Anda nyatakan dalam Algol 68 biasanya adalah referensi, yang kemudian diinisialisasi untuk merujuk pada sesuatu yang dialokasikan pada heap, dan yang (secara opsional) diinisialisasi untuk mengandung beberapa nilai tertentu. Tidak seperti Java, bagaimanapun, mereka setidaknya mencoba membiarkan Anda mempertahankan sintaksis waras untuk itu daripada terus-menerus memiliki hal-hal sepertifoo bar = new foo();
atau mencoba untuk memberitahu fibs tentang "pointer kami bukan pointer."Pascal dan sebagian besar turunannya (baik langsung maupun ... spiritual) mengganti nama konsep referensi Algol 68 menjadi "pointer" tetapi mempertahankan konsep itu sendiri pada dasarnya tetap sama: pointer adalah variabel yang menahan
nil
, atau alamat dari sesuatu yang Anda alokasikan pada heap (yaitu, setidaknya seperti yang didefinisikan oleh Jensen dan Wirth, tidak ada operator "address-of", jadi tidak ada cara bagi pointer untuk merujuk ke variabel yang didefinisikan secara normal). Meskipun "pointer", aritmatika pointer tidak didukung.C dan C ++ menambahkan beberapa tikungan untuk itu. Pertama, mereka memang memiliki alamat-operator, sehingga pointer dapat merujuk tidak hanya pada sesuatu yang dialokasikan pada heap, tetapi juga pada variabel apa pun, terlepas dari bagaimana dialokasikan. Kedua, mereka mendefinisikan aritmatika pada pointer - dan mendefinisikan subscript array sebagai dasarnya hanya notasi singkat untuk aritmatika pointer, sehingga aritmatika pointer ada di mana-mana (di samping tidak dapat dihindari) di sebagian besar C dan C ++.
Ketika Java ditemukan, Sun rupanya mengira "Java tidak memiliki pointer" adalah pesan pemasaran yang lebih sederhana dan lebih bersih daripada: "hampir semua yang ada di Jawa adalah pointer, tetapi pointer ini kebanyakan seperti Pascal, bukan C." Karena mereka memutuskan "penunjuk" bukan istilah yang dapat diterima, mereka membutuhkan sesuatu yang lain, dan malah "mengeruk" referensi, meskipun referensi mereka secara halus (dan dalam beberapa kasus tidak begitu halus) berbeda dari referensi Algol 68.
Meskipun itu keluar agak berbeda, C ++ terjebak dengan masalah yang kira-kira sama: kata "pointer" sudah dikenal dan dipahami, jadi mereka membutuhkan kata yang berbeda untuk hal yang berbeda yang mereka tambahkan yang merujuk ke sesuatu yang lain, tetapi sebaliknya cukup sedikit berbeda dari apa yang orang pahami "penunjuk" artinya. Jadi, meskipun itu juga sangat berbeda dari referensi Algol 68, mereka juga menggunakan istilah "referensi".
sumber
Notion dari 'tipe referensi' adalah yang generik, dapat mengekspresikan pointer dan referensi (dalam hal C ++), sebagai lawan dari 'tipe nilai'. Referensi Jawa benar-benar pointer tanpa biaya overhead sintaksis dari
->
sebuah*
dereferencing. Jika Anda melihat implementasi JVM di C ++, mereka benar-benar petunjuk kosong. Juga, C # memiliki gagasan referensi yang mirip dengan Java, tetapi juga memiliki pointer dan 'ref' kualifikasi pada parameter fungsi, yang memungkinkan untuk meneruskan tipe-nilai dengan referensi dan menghindari penyalinan seperti&
di C ++.sumber