Bagaimana referensi Java berbeda dari pointer C?

97

C memiliki pointer dan Java memiliki apa yang disebut referensi. Mereka memiliki beberapa kesamaan dalam arti bahwa mereka semua menunjuk pada sesuatu. Saya tahu bahwa pointer di C menyimpan alamat yang mereka tuju. Apakah referensi juga menyimpan alamatnya? Bagaimana mereka berbeda kecuali bahwa pointer lebih fleksibel dan rawan kesalahan?

Gnijuohz
sumber
10
Catatan C ++ juga memiliki referensi yang berbeda dengan pointer atau referensi java
jk.
@jk. Saya pikir itu akan sama dengan di Jawa. Apa bedanya?
Gnijuohz
17
Referensi C ++ tidak dapat di-rebindable (artinya Anda tidak dapat mengubah objek yang ditunjuk) dan tidak dapat dibatalkan (yaitu Anda tidak dapat meminta mereka untuk referensi tanpa objek sama sekali).
Pemrogram
@Gnijuohz Mengulangi apa yang dikatakan @AProgrammer: finalReferensi di Jawa hampir setara dengan referensi C ++. Alasan bahwa mereka tidak persis sama adalah, referensi C ++ juga tidak dapat dibatalkan, sedangkan finalreferensi di Jawa adalah nullable.
Utku

Jawaban:

142

Referensi dapat diimplementasikan dengan menyimpan alamat. Biasanya referensi Java akan diimplementasikan sebagai pointer, tetapi itu tidak diperlukan oleh spesifikasi. Mereka mungkin menggunakan lapisan tipuan tambahan untuk memungkinkan pengumpulan sampah lebih mudah. Tetapi pada akhirnya itu akan (hampir selalu) bermuara pada pointer (gaya-C) yang terlibat dalam implementasi referensi (gaya Jawa).

Anda tidak dapat melakukan aritmatika pointer dengan referensi. Perbedaan paling penting antara pointer di C dan referensi di Java adalah bahwa Anda tidak bisa benar-benar mendapatkan (dan memanipulasi) nilai yang mendasari referensi di Java. Dengan kata lain: Anda tidak dapat melakukan pointer aritmatika.

Dalam C Anda dapat menambahkan sesuatu ke pointer (yaitu alamat) atau mengurangi sesuatu untuk menunjuk ke hal-hal yang "dekat" atau arahkan ke tempat-tempat yang ada di tempat mana pun .

Di Jawa, referensi menunjuk ke satu hal dan hanya itu. Anda dapat membuat variabel memiliki referensi yang berbeda , tetapi Anda tidak bisa hanya memintanya untuk menunjuk ke "hal setelah hal yang asli".

Referensi sangat diketik. Perbedaan lainnya adalah bahwa jenis referensi jauh lebih ketat dikendalikan di Jawa daripada jenis pointer di C. Di C Anda dapat memiliki int*dan melemparkannya ke char*dan hanya menafsirkan kembali memori di lokasi itu. Penafsiran ulang itu tidak berfungsi di Jawa: Anda hanya bisa menginterpretasikan objek di ujung referensi lain sebagai sesuatu yang sudah ada (yaitu Anda dapat melemparkan Objectreferensi ke Stringreferensi hanya jika objek yang ditunjuk sebenarnya a String).

Perbedaan itu membuat pointer C lebih kuat, tetapi juga lebih berbahaya. Kedua kemungkinan tersebut (pointer aritmatika dan menafsirkan kembali nilai-nilai yang ditunjukkan) menambah fleksibilitas untuk C dan merupakan sumber dari beberapa kekuatan bahasa. Tetapi mereka juga merupakan sumber masalah besar, karena jika digunakan secara tidak benar mereka dapat dengan mudah mematahkan asumsi bahwa kode Anda dibangun. Dan cukup mudah untuk menggunakannya secara salah.

Joachim Sauer
sumber
18
+1 untuk mungkin . Jangan mengandalkan detail implementasi.
CVn
2
+1 Bukankah pengumpulan sampah layak disebutkan sebagai titik tebal tertentu? Ini adalah cara lain bahwa pointer C lebih kuat tetapi juga lebih berbahaya (risiko pointer menggantung ke memori yang bebas menyebabkan kerusakan memori, risiko kebocoran memori)
MarkJ
Perbedaan lain antara referensi dan pointer adalah bahwa pointer di C dapat dikonversi menjadi urutan angka (misalnya dengan menggunakan memcpyuntuk memindahkan satu ke a char[]) dan sebaliknya. Jika pointer dikonversi ke urutan angka yang disimpan di suatu tempat (mungkin ditampilkan di layar dan disalin oleh operator pada selembar kertas), semua salinan pointer di komputer dihancurkan, dan urutan angka dikonversi kembali ke pointer (mungkin setelah diketik oleh operator), pointer masih harus menunjuk ke hal yang sama seperti sebelumnya. Sebuah program yang ...
supercat
... menampilkan penunjuk sebagai angka, dan kemudian mengonversi angka yang dimasukkan secara manual ke sebuah penunjuk, mungkin "jahat", tetapi itu tidak akan memanggil Perilaku Tidak Terdefinisi apa pun kecuali operator mengetikkan angka yang tidak ditunjukkan untuk membentuk valid penunjuk. Dengan demikian pengumpulan sampah untuk keperluan umum tidak mungkin dilakukan dalam C yang sepenuhnya portabel, karena tidak mungkin komputer dapat mengetahui apakah salinan penunjuk mungkin ada di suatu tempat di alam semesta.
supercat
Menurut JLS, §4.3.1, referensi di Jawa adalah pointer, jadi "Biasanya referensi Java akan diimplementasikan sebagai pointer, tetapi itu tidak diperlukan oleh spesifikasi." itu salah.
Lew Bloch
8

Referensi C ++ berbeda lagi.

Mereka harus diinisialisasi dan tidak boleh nol (setidaknya tidak dalam program yang dibentuk dengan baik) dan tidak dapat diulang untuk merujuk ke sesuatu yang lain. referensi C ++ jauh lebih seperti alias untuk objek.

Perbedaan penting lainnya antara pointer dan referensi Java / C ++ adalah bahwa Anda dapat mengambil alamat penunjuk yang Anda tidak dapat mengakses alamat referensi (memang referensi C ++ tidak perlu benar-benar ada sebagai objek di memori sama sekali) akibatnya Anda dapat memiliki pointer ke pointer tetapi bukan referensi ke referensi

jk.
sumber
4

Referensi Java dan pointer C berbeda persis dalam dua poin:

  1. Tidak ada pointer-aritmatika untuk yang pertama.
  2. Dan Anda tidak dapat membuat referensi Java ke apa pun yang Anda inginkan, Anda hanya dapat menyalin yang disimpan di suatu tempat yang dapat diakses (bidang statis, bidang objek, variabel lokal) atau dikembalikan oleh fungsi-doa (seperti panggilan konstruktor), yang dengan demikian semuanya merujuk ke Jawa objek (tidak pernah ke tipe dasar seperti referensi char,, intdan sebagainya).

Seseorang menulis bahwa Referensi sangat diketik, karena Anda tidak dapat memaksa kompiler untuk memperlakukan int*sebagai a char*.
Sepenuhnya terlepas dari kenyataan bahwa konversi tertentu sebenarnya aman , tidak ada polimorfisme dalam C, sehingga perbandingan adalah non-starter.
Tentu saja, Java lebih kuat daripada C, bukan berarti itu fitur C pointer vs Java referensi, Anda perlu menggunakan JNI untuk memecah keamanan tipe (selain mengabaikan pembatasan generik), tetapi bahkan dalam C Anda harus memaksa kompiler.

Seseorang menulis bahwa Java referensi mungkin dilaksanakan sebagai C pointer, yang saya katakan yakin, karena mereka secara ketat kurang kuat, pada mesin 32bit mereka biasanya adalah, jika JVM diimplementasikan dalam C . Meskipun pada mesin 64bit, mereka biasanya dikompresi pointer-objek biasa ("OOP terkompresi") untuk menghemat ruang dan bandwidth.
Pokoknya, pointer C tersebut juga tidak harus setara dengan alamat perangkat keras, bahkan jika biasanya (> 99% implementasi) adalah untuk alasan kinerja.
Akhirnya, itu adalah detail implementasi yang tidak terpapar ke programmer.

Deduplicator
sumber
-1

Mereka sedikit berbeda. Di Jawa, salinan referensi disalin ke tumpukan fungsi yang dipanggil, menunjuk ke objek yang sama dengan fungsi panggilan dan memungkinkan Anda untuk memanipulasi objek itu. Namun Anda tidak dapat mengubah objek yang mengacu pada fungsi panggilan.

Pertimbangkan kode java berikut

public static void changeRValue(StringBuffer sb){
    sb = new StringBuffer("helllllo"); /*attempt to assign the reference
                                        to a new object*/
}
public static void main(String[] args) {
    StringBuffer sb = new StringBuffer("hi");     //Create a new string buffer
    changeRValue(sb);                             //Call changeRValue
    System.out.println(sb.toString());            //Prints "hi" not "hello"
}

Sekarang pertimbangkan sebuah pointer di c ++:

void func(Dog* dog){
    *dog = Dog("hello world"); //Change the value of dog to a new object
}

int main(int argc, const char * argv[]) {
    Dog dog1("hi");                            //Create a dog object
    func(&dog1);                               //pass the address of dog
    cout << dog1.name;                         //Prints "hello world" not hi.
    return 0;
}
Eladian
sumber
Saya pikir saya dapat menambahkan bahwa itu dapat dilihat sebagai mirip dengan Dog * const
Eladian
2
Anda dapat memodifikasi objek runcing ke di Jawa dengan kemudahan yang sama seperti di C ++. Anda hanya perlu memiliki akses ke anggota yang tepat. Objek Java tidak memiliki operator penugasan karena Java tidak mendukung overloading yang ditentukan pengguna, jadi Anda tidak dapat menggunakan operator yang kelebihan beban, masalah besar. Kurangnya Java tidak ada hubungannya dengan fakta bahwa referensi Java sama dengan C ++ pointer kehilangan pointer-aritmatika.
Deduplicator