Mengapa tidak == perbandingan nilai string operator membuatnya ke Java?

50

Setiap programmer Java yang kompeten tahu bahwa Anda perlu menggunakan String.equals () untuk membandingkan string, bukan == karena == memeriksa persamaan referensi.

Ketika saya berurusan dengan string, sebagian besar waktu saya memeriksa kesetaraan nilai daripada kesetaraan referensi. Tampaknya bagi saya bahwa akan lebih intuitif jika bahasa memungkinkan nilai string dibandingkan dengan hanya menggunakan ==.

Sebagai perbandingan, operator C # == memeriksa kesetaraan nilai untuk string . Dan jika Anda benar-benar perlu memeriksa persamaan referensi, Anda dapat menggunakan String.ReferenceEquals.

Poin penting lainnya adalah bahwa String tidak dapat diubah, sehingga tidak ada salahnya dilakukan dengan mengizinkan fitur ini.

Apakah ada alasan khusus mengapa ini tidak diterapkan di Jawa?

lk
sumber
12
Anda mungkin ingin melihat Scala, di mana ==objek kesetaraan dan eqreferensi kesetaraan ( ofps.oreilly.com/titles/9780596155957/… ).
Giorgio
Sama seperti catatan, dan ini mungkin tidak membantu Anda, tetapi sejauh yang saya ingat, Anda dapat membandingkan string literal dengan '=='
Kgrover
10
@Kgrover: Anda bisa, tapi itu hanya produk sampingan dari persamaan referensi dan bagaimana Java secara agresif mengoptimalkan string string literal ke dalam referensi ke objek yang sama. Dengan kata lain, itu berhasil, tetapi untuk alasan yang salah.
tdammers
1
@aviv ==operator hanya memetakan Equalsjika ==operator dilaksanakan dengan cara itu. Perilaku default untuk ==adalah sama dengan ReferenceEquals(sebenarnya, ReferenceEqualsdidefinisikan sebagai versi objek ==)
Patrick Huizinga
3
Ini adalah konsekuensi dari keputusan desain yang masuk akal dalam banyak skenario lainnya. Tetapi karena Anda sepertinya tahu itu dan menanyakan hal ini, saya merasa terdorong untuk menjawab pertanyaan Anda: Mengapa harus ada use case untuk perbandingan referensi String?
Jacob Raihle

Jawaban:

90

Saya kira itu hanya konsistensi, atau "prinsip paling tidak heran". String adalah objek, sehingga akan mengejutkan jika diperlakukan berbeda dari objek lain.

Pada saat Java keluar (~ 1995), hanya memiliki sesuatu seperti Stringadalah kemewahan total bagi sebagian besar programmer yang terbiasa merepresentasikan string sebagai array yang diakhiri dengan null. StringPerilaku sekarang adalah apa yang dulu, dan itu bagus; mengubah perilaku secara halus di kemudian hari dapat memiliki efek yang mengejutkan dan tidak diinginkan dalam program kerja.

Sebagai catatan tambahan, Anda dapat menggunakan String.intern()untuk mendapatkan representasi canonical (diinternir) dari string, setelah itu perbandingan dapat dibuat ==. Magang membutuhkan waktu, tetapi setelah itu, perbandingan akan sangat cepat.

Tambahan: tidak seperti beberapa jawaban yang disarankan, ini bukan tentang mendukung kelebihan operator . The +operator (concatenation) bekerja pada Strings meskipun Java tidak mendukung operator overloading; itu hanya ditangani sebagai kasus khusus di kompiler, diselesaikan StringBuilder.append(). Demikian pula, ==bisa ditangani sebagai kasus khusus.

Lalu mengapa heran dengan kasus khusus +tetapi tidak dengan ==? Karena, +tidak dikompilasi ketika diterapkan pada non- Stringobjek sehingga cepat terlihat. Perbedaan perilaku dari ==akan jauh lebih jelas dan dengan demikian jauh lebih mencengangkan ketika hits Anda.

Joonas Pulakka
sumber
8
Kasus khusus menambah keheranan.
Blrfl
17
String adalah barang mewah pada tahun 1995? Benarkah?? Lihatlah sejarah bahasa komputer. Jumlah bahasa yang memiliki beberapa jenis string pada saat itu akan jauh melebihi jumlah yang tidak. Berapa banyak bahasa selain C dan keturunannya yang menggunakan array yang diakhiri nol?
WarrenT
14
@ WarrenT: Tentu, beberapa (jika tidak sebagian besar) bahasa memiliki beberapa jenis string, tetapi Unicode-mampu, string yang dikumpulkan sampah adalah hal yang baru pada tahun 1995, saya pikir. Sebagai contoh, Python memperkenalkan string Unicode dengan versi 2.0, tahun 2000. Memilih immutability juga merupakan pilihan kontroversial pada waktu itu.
Joonas Pulakka
3
@JoonasPulakka Maka mungkin Anda harus mengedit jawaban Anda untuk mengatakan itu. Karena seperti berdiri, bagian "total kemewahan" dari jawaban Anda cukup salah.
svick
1
Interning memiliki biaya: Anda mendapatkan string yang tidak akan pernah dapat dibatalkan alokasinya. (Yah, tidak, kecuali jika Anda menggunakan mesin interning Anda sendiri yang dapat Anda buang.)
Donal Fellows
32

James Gosling , pencipta Jawa, menjelaskannya pada Juli 2000 :

Saya membiarkan operator kelebihan beban sebagai pilihan yang cukup pribadi karena saya telah melihat terlalu banyak orang menyalahgunakannya di C ++. Saya telah menghabiskan banyak waktu dalam lima hingga enam tahun terakhir untuk mensurvei orang-orang tentang kelebihan operator dan ini sangat menarik, karena Anda membuat komunitas terbagi menjadi tiga bagian: Mungkin sekitar 20 hingga 30 persen dari populasi berpikir operator kelebihan beban sebagai menelurkan iblis; seseorang telah melakukan sesuatu dengan operator kelebihan yang baru saja menandai mereka, karena mereka telah menggunakan + untuk penyisipan daftar dan itu membuat hidup benar-benar membingungkan. Banyak dari masalah itu berasal dari kenyataan bahwa hanya ada sekitar setengah lusin operator yang bisa masuk akal, tetapi ada ribuan atau jutaan operator yang ingin ditentukan orang - jadi Anda harus memilih,

Ross Patterson
sumber
50
Ah, ya, yang lama "mari kita menumpulkan alat yang runcing sehingga oafs tidak akan melukai diri sendiri" alasan.
Blrfl
22
@ Blrfl: Jika alat menciptakan lebih banyak masalah daripada memecahkannya itu bukan alat yang baik. Tentu saja, memutuskan apakah ini yang terjadi dengan overloading operator dapat berubah menjadi diskusi yang sangat panjang.
Giorgio
15
-1. Ini sama sekali tidak menjawab pertanyaan. Java memang memiliki kelebihan operator. The ==operator kelebihan beban untuk objek dan primitif. The +operator kelebihan beban untuk byte, short, int, long, float, double, Stringdan mungkin beberapa orang lain yang saya lupa. Itu akan sangat mungkin untuk kelebihan ==untuk Stringjuga.
Jörg W Mittag
10
@ Jorg - tidak, tidak. Overloading operator tidak mungkin ditentukan di tingkat pengguna. Memang ada beberapa kasus khusus dalam kompiler tetapi hampir tidak memenuhi syarat
AZ01
9
@ Blrfl: Saya tidak keberatan oaf menyakiti diri mereka sendiri. Ketika mereka secara tidak sengaja mencungkil mataku, aku jadi kesal.
Jonas
9

Konsistensi dalam bahasa. Memiliki operator yang bertindak berbeda dapat mengejutkan bagi programmer. Java tidak memungkinkan pengguna untuk membebani operator - karena itu referensi kesetaraan adalah satu-satunya makna yang masuk akal untuk ==antar objek.

Di dalam jawa:

  • Antara tipe numerik, ==bandingkan persamaan numerik
  • Di antara tipe boolean, ==bandingkan kesetaraan boolean
  • Antara objek, ==bandingkan identitas referensi
    • Gunakan .equals(Object o)untuk membandingkan nilai

Itu dia. Aturan sederhana dan mudah untuk mengidentifikasi apa yang Anda inginkan. Ini semua tercakup dalam bagian 15.21 JLS . Ini terdiri dari tiga subbagian yang mudah dipahami, diterapkan, dan dipikirkan.

Setelah Anda mengizinkan overloading== , perilaku yang tepat bukanlah sesuatu yang bisa Anda lihat di JLS dan letakkan jari Anda pada item tertentu dan katakan "begitulah cara kerjanya," kodenya bisa menjadi sulit untuk dipikirkan. Perilaku tepat ==mungkin mengejutkan bagi pengguna. Setiap kali Anda melihatnya, Anda harus kembali dan memeriksa untuk melihat apa artinya sebenarnya.

Karena Java tidak memungkinkan untuk overloading operator, orang perlu cara untuk memiliki tes kesetaraan nilai yang Anda dapat menimpa definisi dasar. Jadi, itu dimandatkan oleh pilihan desain ini. ==di Java menguji numerik untuk tipe numerik, kesetaraan boolean untuk tipe boolean, dan referensi kesetaraan untuk yang lainnya (yang dapat menggantikan .equals(Object o)untuk melakukan apa pun yang mereka inginkan untuk kesetaraan nilai).

Ini bukan masalah "apakah ada kasus penggunaan untuk konsekuensi tertentu dari keputusan desain ini" melainkan "ini adalah keputusan desain untuk memfasilitasi hal-hal lain ini, ini adalah konsekuensi dari itu."

String magang , adalah salah satu contohnya. Menurut JLS 3.10.5 , semua string literal diinternir. String lain diinternir jika seseorang memintanya .intern(). Itu "foo" == "foo"benar adalah konsekuensi dari keputusan desain yang dibuat untuk meminimalkan jejak memori yang diambil oleh String literal. Di luar itu, String interning adalah sesuatu yang ada di level JVM yang memiliki sedikit eksposur kepada pengguna, tetapi dalam sebagian besar kasus, seharusnya tidak menjadi sesuatu yang menyangkut programmer (dan menggunakan case untuk programmer tidak sesuatu yang tinggi dalam daftar untuk para desainer ketika mempertimbangkan fitur ini).

Orang-orang akan menunjukkan itu +dan +=kelebihan beban untuk String. Namun, itu tidak penting. Tetap menjadi kasus bahwa jika ==memiliki makna kesetaraan nilai untuk String (dan hanya String), orang akan membutuhkan metode yang berbeda (yang hanya ada dalam String) untuk referensi kesetaraan. Selanjutnya, ini akan metode sia-sia menyulitkan yang mengambil Obyek dan berharap ==untuk berperilaku salah satu cara dan .equals()berperilaku lain pengguna yang membutuhkan untuk kasus khusus semua orang metode untuk String.

Kontrak yang konsisten untuk ==pada Objects adalah bahwa itu hanya referensi kesetaraan dan yang .equals(Object o)ada untuk semua objek yang harus menguji kesetaraan nilai. Rumitnya hal ini merumitkan terlalu banyak hal.


sumber
Terima kasih telah meluangkan waktu untuk menjawab. Ini akan menjadi jawaban yang bagus untuk pertanyaan-pertanyaan lain yang saya tautkan. Sayangnya, ini tidak cocok untuk pertanyaan ini. Saya akan memperbarui OP dengan klarifikasi berdasarkan komentar. Saya mencari lebih banyak untuk kasus penggunaan di mana pengguna bahasa ingin memiliki false-negatif ketika membandingkan string. Bahasa ini menyediakan fitur ini sebagai konsistensi, sekarang saya ingin kita melangkah lebih jauh. Mungkin memikirkan ini dari perancang bahasa baru, apakah itu dibutuhkan? (sayangnya, tidak ada lang-design.SE)
Anonsage
3
@Anageage bukan negatif palsu. Mereka bukan objek yang sama. Hanya itu yang dikatakan. Saya juga harus menunjukkan bahwa di Java 8, new String("foo") == new String("foo")mungkin benar (lihat Deduplication String ).
1
Mengenai desain bahasa, CS.SE mengiklankan bahwa mungkin ada topik di sana.
ooh terima kasih! Saya akan memposting pertanyaan lang-desain masa depan saya di sana. :) Dan, ya, sayangnya 'false-negative' bukan cara yang paling akurat untuk menggambarkan pertanyaan saya dan apa yang saya cari .. Saya perlu menulis lebih banyak kata sehingga orang tidak perlu menebak apa yang saya mencoba mengatakan.
Anonsage
2
"Konsistensi dalam bahasa" juga membantu dengan obat generik
Brendan
2

Java tidak mendukung overloading operator, yang berarti ==hanya berlaku untuk tipe atau referensi primitif. Yang lainnya membutuhkan doa metode. Mengapa perancang melakukan ini adalah pertanyaan yang hanya bisa mereka jawab. Jika saya harus menebak, itu mungkin karena kelebihan operator membawa kerumitan yang mereka tidak ingin tambahkan.

Saya bukan ahli dalam C #, tetapi perancang bahasa itu tampaknya telah mengaturnya sehingga setiap primitif adalah structdan setiap structobjek. Karena C # memungkinkan overloading operator, pengaturan itu membuatnya sangat mudah untuk semua kelas, tidak hanya String, untuk membuatnya bekerja dengan cara yang "diharapkan" dengan operator mana pun. C ++ memungkinkan hal yang sama.

Blrfl
sumber
1
"Java tidak mendukung overloading operator, yang berarti == hanya berlaku untuk tipe atau referensi primitif. Apa pun yang lain memerlukan pemanggilan metode.": Orang dapat menambahkan bahwa jika ==dimaksudkan kesetaraan string, kita akan memerlukan notasi lain untuk kesetaraan referensi.
Giorgio
@Iorgio: Tepat. Lihat komentar saya tentang jawaban Gilad Naaman.
Blrfl
Meskipun itu dapat diselesaikan dengan metode statis yang membandingkan referensi dari dua objek (atau operator). Seperti di C #, misalnya.
Gilad Naaman
@GiladNaaman: Itu akan menjadi permainan zero-sum karena menyebabkan masalah yang berlawanan dengan apa yang dimiliki Java sekarang: kesetaraan akan ada pada operator dan Anda harus menggunakan metode untuk membandingkan referensi. Selanjutnya, Anda harus memaksakan persyaratan bahwa semua kelas mengimplementasikan sesuatu yang dapat diikat ==. Itu secara efektif menambah kelebihan operator, yang akan memiliki implikasi luar biasa pada cara Java diimplementasikan.
Blrfl
1
@ Blrfl: Tidak juga. Akan selalu ada cara yang ditentukan untuk membandingkan referensi ( ClassName.ReferenceEquals(a,b)), dan ==operator dan Equalsmetode default keduanya menunjuk ke ReferenceEquals.
Gilad Naaman
2

Ini telah dibuat berbeda dalam bahasa lain.

Dalam Object Pascal (Delphi / Free Pascal) dan C #, operator persamaan didefinisikan untuk membandingkan nilai, bukan referensi, ketika beroperasi pada string.

Khususnya di Pascal, string adalah tipe primitif (salah satu hal yang sangat saya sukai tentang Pascal, mendapatkan NullreferenceException hanya karena string yang tidak diinisialisasi hanya menjengkelkan) dan memiliki semantik copy-on-write sehingga membuat (sebagian besar) operasi string sangat murah (dengan kata lain, hanya terlihat setelah Anda mulai merangkai string multi-megabyte).

Jadi, ini adalah keputusan desain bahasa untuk Java. Ketika mereka mendesain bahasa mereka mengikuti cara C ++ (seperti Std :: String) sehingga string adalah objek, yang merupakan peretasan IMHO untuk mengkompensasi C yang tidak memiliki tipe string nyata, alih-alih menjadikan string sebagai primitif (yang mana mereka).

Jadi untuk alasan mengapa, saya hanya bisa berspekulasi mereka membuatnya mudah di pihak mereka dan tidak mengkode operator membuat pengecualian pada compiler ke string.

Fabricio Araujo
sumber
bagaimana ini menjawab pertanyaan yang diajukan?
Agak
Lihat kalimat terakhir (yang saya pisahkan dalam paragraf yang tepat dalam sunting).
Fabricio Araujo
1
IMHO, Stringseharusnya menjadi tipe primitif di Jawa. Tidak seperti tipe lain, kompiler perlu tahu tentang String; lebih lanjut, operasi pada itu akan cukup umum bahwa untuk banyak jenis aplikasi mereka dapat menimbulkan hambatan kinerja (yang dapat dikurangi dengan dukungan asli). string[Huruf kecil] tipikal akan memiliki objek yang dialokasikan pada heap untuk menampung isinya, tetapi tidak ada referensi "normal" untuk objek itu yang ada di mana saja; dengan demikian bisa menjadi satu-diarahkan Char[]atau Byte[]daripada harus menjadi diarahkan Char[]melalui objek lain.
supercat
1

Di Jawa, tidak ada operator kelebihan beban apa pun, dan itulah sebabnya operator pembanding hanya kelebihan beban untuk tipe primitif.

Kelas 'String' bukan primitif, sehingga tidak memiliki overloading untuk '==' dan menggunakan default untuk membandingkan alamat objek dalam memori komputer.

Saya tidak yakin, tapi saya berpikir bahwa di Jawa 7 atau 8 oracle membuat pengecualian dalam compiler untuk mengenali str1 == str2sebagaistr1.equals(str2)

Gilad Naaman
sumber
"Saya tidak yakin, tapi saya pikir di Java 7 atau 8 oracle membuat pengecualian di kompiler untuk mengenali str1 == str2 sebagai str1.equals (str2)": Saya tidak akan terkejut: Oracle tampaknya kurang peduli dengan minimalisme daripada Sun.
Giorgio
2
Jika benar, itu peretasan yang sangat jelek karena itu berarti sekarang ada satu kelas yang berbeda dari bahasa lainnya dan memecah kode yang membandingkan referensi. : - @
Blrfl
1
@ WillihamTotland: Pertimbangkan kasus sebaliknya. Saat ini, jika saya membuat dua string, s1dan s2dan memberi mereka konten yang sama, mereka melewati s1.equals(s2)perbandingan kesetaraan ( ) tetapi bukan perbandingan referensi yang sama ( ==) karena mereka dua objek yang berbeda. Mengubah semantik ==menjadi kesetaraan akan menyebabkan s1 == s2untuk mengevaluasi di truemana ia digunakan untuk mengevaluasi false.
Blrfl
2
@ Brrfl: Walaupun itu benar, itu kedengarannya seperti hal yang sangat buruk untuk mengandalkan pada awalnya, karena string adalah objek yang tidak dapat diubah dan tidak dapat dioperasi.
Williham Totland
2
@Giorgio: "Java 7 atau 8 oracle membuat pengecualian dalam kompiler untuk mengenali str1 == str2 sebagai str1.equals (str2)" Tidak, Spesifikasi Bahasa Jawa mengatakan: Referensi Persamaan Operator : "Jika operan dari operator kesetaraan adalah baik dari tipe referensi atau tipe nol, maka operasinya adalah persamaan objek. " Itu semua orang. Saya juga tidak menemukan sesuatu yang baru tentang ini di draft awal Java 8 .
David Tonhofer
0

Java tampaknya telah dirancang untuk menegakkan aturan mendasar bahwa ==operator harus sah setiap kali satu operan dapat dikonversi ke jenis yang lain, dan harus membandingkan hasil konversi tersebut dengan operan yang tidak dikonversi.

Aturan ini hampir tidak unik untuk Java, tetapi memiliki beberapa efek jangkauan (dan IMHO sial) pada desain aspek-aspek terkait bahasa lainnya. Akan lebih bersih untuk menentukan perilaku ==sehubungan dengan kombinasi tertentu dari tipe operan, dan melarang kombinasi tipe X dan Y di mana x1==y1dan x2==y1tidak akan menyiratkan x1==x2, tetapi bahasa jarang melakukan itu [di bawah filosofi itu, double1 == long1harus menunjukkan apakah double1bukan representasi yang tepat dari long1, atau menolak untuk dikompilasi;int1==Integer1harus dilarang, tetapi harus ada cara non-lempar yang nyaman dan efisien untuk menguji apakah suatu objek bilangan bulat kotak dengan nilai tertentu (perbandingan dengan sesuatu yang bukan bilangan bulat kotak seharusnya dikembalikan false)].

Sehubungan dengan menerapkan ==operator ke string, jika Jawa telah melarang perbandingan langsung antara operan tipe Stringdan Object, itu bisa menghindari kejutan dalam perilaku ==, tetapi tidak ada perilaku yang bisa diterapkan untuk perbandingan seperti itu yang tidak akan mengejutkan. Memiliki dua string string yang disimpan dalam tipe Objectberperilaku berbeda dari referensi yang disimpan dalam tipe Stringakan jauh lebih mencengangkan daripada memiliki salah satu perilaku tersebut berbeda dari perbandingan tipe campuran legal. Jika String1==Object1legal, itu akan menyiratkan bahwa satu-satunya cara untuk perilaku String1==String2dan Object1==Object2untuk mencocokkan String1==Object1adalah bagi mereka untuk saling mencocokkan.

supercat
sumber
Saya harus melewatkan sesuatu, tetapi IMHO ==pada objek hanya harus memanggil (null-safe) sama dengan dan sesuatu yang lain (misalnya, ===atau System.identityEqual) harus digunakan untuk perbandingan identitas. Mencampur primitif dan objek pada awalnya dilarang (tidak ada autobox sebelum 1,5) dan kemudian beberapa aturan sederhana dapat ditemukan (mis. Null-safe unbox, lalu cast, lalu bandingkan).
maaartinus
@maaartinus: Desain bahasa yang baik harus menggunakan operator kesetaraan terpisah untuk kesetaraan nilai dan referensi. Sementara saya setuju bahwa secara konseptual akan mungkin untuk memiliki pengembalian int==Integeroperator falsejika Integernol, dan jika tidak membandingkan nilai-nilai, pendekatan itu tidak seperti perilaku ==dalam semua keadaan lain, di mana ia tanpa syarat memaksa kedua operan untuk jenis yang sama sebelum membandingkan mereka. Secara pribadi saya bertanya-tanya apakah auto-unboxing diberlakukan sebagai upaya untuk memungkinkan int==Integeruntuk memiliki perilaku yang tidak masuk akal ...
supercat
... sejak melakukan autoboxing intdan melakukan perbandingan referensi akan konyol [tetapi tidak selalu gagal]. Kalau tidak, saya tidak melihat alasan untuk mengizinkan konversi implisit yang dapat gagal dengan NPE.
supercat
Saya pikir ide saya konsisten. Hanya perlu diingat bahwa di dunia yang lebih baik, ==tidak ada hubungannya dengan identityEquals. +++ "operator kesetaraan terpisah untuk kesetaraan nilai dan referensi" - tetapi yang mana? Saya akan mempertimbangkan baik primitif ==maupun equalssebagai melakukan perbandingan nilai dalam arti yang equalsterlihat pada nilai referensi. +++ Ketika ==dimaksud equals, maka int==IntegerHARUS melakukan autoboxing dan membandingkan referensi menggunakan null-safe sama dengan. +++ Aku takut, ideku bukan milikku, tapi apa yang Kotlin lakukan.
maaartinus
@maaartinus: Jika ==tidak pernah menguji kesetaraan referensi, maka secara masuk akal dapat melakukan uji kesetaraan nilai-aman-nol. Fakta bahwa itu tidak kesetaraan referensi tes, bagaimanapun, sangat membatasi bagaimana dapat menangani perbandingan referensi / nilai campuran tanpa inkonsistensi. Perhatikan juga bahwa Java ditetapkan pada anggapan bahwa operator mempromosikan kedua operan ke tipe yang sama, daripada menghasilkan perilaku khusus berdasarkan kombinasi tipe yang terlibat. Sebagai contoh, 16777217==16777216.0fkembali truekarena melakukan konversi lossy dari operan pertama ke float, sementara ...
supercat
0

Secara umum, ada alasan yang sangat bagus untuk dapat menguji apakah dua referensi objek menunjuk ke objek yang sama. Saya sudah banyak kali menulis

Address oldAddress;
Address newAddress;
... populate values ...
if (oldAddress==newAddress)
... etc ...

Saya mungkin atau mungkin tidak memiliki fungsi yang sama dalam kasus tersebut. Jika saya lakukan, fungsi equals dapat membandingkan seluruh konten dari kedua objek. Seringkali itu hanya membandingkan beberapa pengidentifikasi. "A dan B adalah referensi ke objek yang sama" dan "A dan B adalah dua objek berbeda dengan konten yang sama", tentu saja, dua ide yang sangat berbeda.

Mungkin benar bahwa untuk objek yang tidak dapat diubah, seperti Strings, ini bukan masalah. Dengan objek yang tidak berubah, kita cenderung menganggap objek dan nilainya sebagai hal yang sama. Nah, ketika saya mengatakan "kita", maksud saya "saya", setidaknya.

Integer three=new Integer(3);
Integer triangle=new Integer(3);
if (three==triangle) ...

Tentu saja itu kembali salah, tetapi saya dapat melihat seseorang berpikir itu harus benar.

Tetapi begitu Anda mengatakan bahwa == membandingkan pegangan referensi dan bukan konten untuk Objek secara umum, membuat kasus khusus untuk Strings akan berpotensi membingungkan. Seperti yang dikatakan orang lain di sini, bagaimana jika Anda ingin membandingkan gagang dua objek String? Apakah akan ada fungsi khusus untuk melakukannya hanya untuk Strings?

Dan bagaimana dengan ...

Object x=new String("foo");
Object y=new String("foo");
if (x==y) ...

Apakah itu salah karena mereka adalah dua objek yang berbeda, atau benar karena mereka adalah string yang isinya sama?

Jadi ya, saya mengerti bagaimana programmer bingung dengan ini. Saya sudah melakukannya sendiri, maksud saya menulis jika myString == "foo" ketika saya maksud jika myString.equals ("foo"). Tapi pendek mendesain ulang arti operator == untuk semua objek, saya tidak melihat bagaimana mengatasinya.

Jay
sumber
Perhatikan bahwa bahasa modern lainnya di JVM, seperti Scala, gunakan ==untuk berarti "string yang sama".
Andres F.
@AndresF. (mengangkat bahu) Di Jawa, "<" berarti "kurang dari", sedangkan dalam XML "membuka tag". Dalam VB "=" dapat berarti "sama dengan", sedangkan di Jawa itu hanya digunakan untuk tugas. Dll. Tidak mengherankan bahwa bahasa yang berbeda menggunakan simbol yang berbeda untuk mengartikan hal yang sama, atau simbol yang sama untuk mengartikan hal yang berbeda.
Jay
Itu bukan penggalian pada jawaban Anda. Itu hanya komentar. Saya baru saja menunjukkan bahwa bahasa yang lebih modern daripada Jawa mengambil kesempatan untuk mendesain ulang makna ==, seperti yang Anda sebutkan di bagian akhir.
Andres F.
@AndresF. Dan jawaban saya bukan menggali komentar Anda, hanya mengatakan bahwa bahasa yang berbeda mendekati masalah ini dengan cara yang berbeda. :-) Saya sebenarnya menyukai cara VB menangani ini ... berhenti sejenak untuk desis dan celaan dari pembenci VB ... "=" selalu membandingkan nilai (untuk tipe yang ditentukan sistem), apakah primitif atau objek. "Is" membandingkan pegangan dua benda. Itu tampaknya lebih intuitif bagi saya.
Jay
Tentu. Tapi Scala jauh lebih dekat ke Jawa daripada Visual Basic. Saya suka berpikir para perancang Scala menyadari bahwa penggunaan Java terhadap ==kesalahan cenderung.
Andres F.
0

Ini adalah pertanyaan yang valid untuk Strings, dan tidak hanya untuk string, tetapi juga untuk Objects berubah lainnya yang mewakili beberapa "nilai", misalnya Double, BigIntegerdan bahkan InetAddress.

Untuk membuat ==operator dapat digunakan dengan String dan kelas nilai lainnya, saya melihat tiga alternatif:

  • Suruh kompiler mengetahui tentang semua kelas nilai ini dan cara membandingkan isinya. Jika itu hanya beberapa kelas dari java.langpaket, saya akan mempertimbangkan itu, tetapi itu tidak mencakup kasus-kasus seperti InetAddress.

  • Izinkan operator overloading sehingga kelas mendefinisikan ==perilaku perbandingannya.

  • Hapus konstruktor publik dan punya metode statis yang mengembalikan instance dari kumpulan, selalu mengembalikan instance yang sama untuk nilai yang sama. Untuk menghindari kebocoran memori, Anda memerlukan sesuatu seperti SoftReferences di pool, yang tidak ada di Java 1.0. Dan sekarang, untuk menjaga kompatibilitas, String()konstruktor tidak dapat dihapus lagi.

Satu-satunya hal yang masih bisa dilakukan hari ini adalah memperkenalkan kelebihan operator, dan secara pribadi saya tidak akan suka Java untuk pergi rute itu.

Bagi saya, keterbacaan kode adalah yang paling penting, dan seorang programmer Java tahu bahwa operator memiliki makna tetap, didefinisikan dalam spesifikasi bahasa, sedangkan metode didefinisikan oleh beberapa kode, dan artinya harus dilihat dalam Javadoc metode. Saya ingin tetap dengan perbedaan itu bahkan jika itu berarti bahwa perbandingan String tidak akan dapat menggunakan ==operator.

Hanya ada satu aspek dari perbandingan Java yang mengganggu saya: efek auto-boxing dan -unboxing. Ini menyembunyikan perbedaan antara tipe primitif dan tipe pembungkus. Tetapi ketika Anda membandingkannya dengan ==, mereka SANGAT berbeda.

    int i=123456;
    Integer j=123456;
    Integer k=123456;
    System.out.println(i==j);  // true or false? Do you know without reading the specs?
    System.out.println(j==k);  // true or false? Do you know without reading the specs?
Ralf Kleberhoff
sumber