Datang dari C ++ ke Java, pertanyaan yang belum terjawab jelas adalah mengapa Java tidak termasuk operator overloading?
Bukankah Complex a, b, c; a = b + c;
lebih sederhana dari itu Complex a, b, c; a = b.add(c);
?
Adakah alasan yang diketahui untuk hal ini, argumen yang valid untuk tidak mengizinkan overloading operator? Apakah alasannya sewenang-wenang, atau hilang waktu?
java
operator-overloading
rengolin
sumber
sumber
Jawaban:
Dengan asumsi Anda ingin menimpa nilai sebelumnya dari objek yang dirujuk oleh
a
, maka fungsi anggota harus dipanggil.Dalam C ++, ekspresi ini memberitahu kompiler untuk membuat tiga (3) objek pada stack, melakukan penambahan, dan menyalin nilai yang dihasilkan dari objek sementara ke objek yang ada
a
.Namun, di Jawa,
operator=
tidak melakukan penyalinan nilai untuk tipe referensi, dan pengguna hanya bisa membuat tipe referensi baru, bukan tipe nilai. Jadi untuk jenis yang ditentukan pengguna bernamaComplex
, tugas berarti menyalin referensi ke nilai yang ada.Pertimbangkan sebagai gantinya:
Dalam C ++, ini menyalin nilainya, sehingga perbandingannya akan menghasilkan tidak sama. Di Jawa,
operator=
melakukan salinan referensi, jadia
danb
sekarang merujuk ke nilai yang sama. Akibatnya, perbandingan akan menghasilkan 'sama', karena objek akan dibandingkan dengan dirinya sendiri.Perbedaan antara salinan dan referensi hanya menambah kebingungan operator yang berlebihan. Seperti yang disebutkan @Sebastian, Java dan C # keduanya harus berurusan dengan nilai dan kesetaraan referensi secara terpisah -
operator+
kemungkinan akan berurusan dengan nilai dan objek, tetapioperator=
sudah diterapkan untuk menangani referensi.Dalam C ++, Anda hanya harus berurusan dengan satu jenis perbandingan pada satu waktu, sehingga bisa kurang membingungkan. Misalnya, aktif
Complex
,operator=
danoperator==
keduanya bekerja pada nilai - nilai menyalin dan membandingkan nilai masing-masing.sumber
Ada banyak postingan yang mengeluhkan kelebihan operator.
Saya merasa saya harus mengklarifikasi konsep "operator overloading", menawarkan sudut pandang alternatif pada konsep ini.
Kode membingungkan?
Argumen ini salah.
Kebingungan dimungkinkan dalam semua bahasa ...
Sangat mudah untuk mengaburkan kode dalam C atau Java melalui fungsi / metode seperti di C ++ melalui overload operator:
... Bahkan di antarmuka standar Java
Sebagai contoh lain, mari kita lihat
Cloneable
antarmuka di Jawa:Anda seharusnya mengkloning objek yang mengimplementasikan antarmuka ini. Tapi kamu bisa berbohong. Dan buat objek yang berbeda. Faktanya, antarmuka ini sangat lemah sehingga Anda bisa mengembalikan jenis objek lain secara bersamaan, hanya untuk bersenang-senang:
Karena
Cloneable
antarmuka dapat disalahgunakan / dikaburkan, haruskah itu dilarang dengan alasan yang sama C ++ operator overload seharusnya?Kita bisa membebani
toString()
metode suatuMyComplexNumber
kelas untuk mengembalikannya pada jam yang ditentukan hari itu. HaruskahtoString()
kelebihan beban juga dilarang? Kita bisa menyabotaseMyComplexNumber.equals
agar mengembalikan nilai acak, memodifikasi operan ... dll dll. Dll.Di Jawa, seperti dalam C ++, atau bahasa apa pun, programmer harus menghormati semantik minimum saat menulis kode. Ini berarti menerapkan
add
fungsi yang menambah, danCloneable
metode implementasi yang mengkloning, dan++
operator daripada penambahan.Apa sih yang membingungkan?
Sekarang kita tahu bahwa kode dapat disabotase bahkan melalui metode Java yang asli, kita dapat bertanya pada diri sendiri tentang penggunaan nyata dari operator yang berlebihan di C ++?
Notasi yang jelas dan alami: metode vs. kelebihan operator?
Kami akan membandingkan di bawah ini, untuk kasus yang berbeda, kode "sama" di Java dan C ++, untuk memiliki gagasan tentang jenis gaya pengkodean yang lebih jelas.
Perbandingan alami:
Harap dicatat bahwa A dan B dapat berupa jenis apa pun dalam C ++, selama operator kelebihan beban disediakan. Di Jawa, ketika A dan B bukan primitif, kode dapat menjadi sangat membingungkan, bahkan untuk objek seperti primitif (BigInteger, dll.) ...
Pengakses dan larik array / wadah alami:
Di Jawa, kami melihat bahwa untuk setiap wadah melakukan hal yang sama (mengakses kontennya melalui indeks atau pengidentifikasi), kami memiliki cara berbeda untuk melakukannya, yang membingungkan.
Di C ++, setiap kontainer menggunakan cara yang sama untuk mengakses kontennya, terima kasih kepada operator yang berlebihan.
Manipulasi tipe lanjutan alami
Contoh di bawah ini menggunakan
Matrix
objek, ditemukan menggunakan tautan pertama yang ditemukan di Google untuk "objek Java Matrix " dan "objek C ++ Matrix ":Dan ini tidak terbatas pada matriks. The
BigInteger
danBigDecimal
kelas Java menderita bertele-tele membingungkan yang sama, sedangkan setara dalam C ++ adalah sebagai jelas seperti built-in jenis.Iterator alami:
Functors alami:
Rangkaian teks:
Ok, di Jawa Anda bisa menggunakan
MyString = "Hello " + 25 + " World" ;
juga ... Tapi, tunggu sebentar: Ini overloading operator, bukan? Bukankah itu curang ???:-D
Kode generik?
Operan pemodifikasi kode generik yang sama harus dapat digunakan baik untuk built-in / primitif (yang tidak memiliki antarmuka di Jawa), objek standar (yang tidak dapat memiliki antarmuka yang tepat), dan objek yang ditentukan pengguna.
Misalnya, menghitung nilai rata-rata dari dua nilai tipe arbitrer:
Membahas kelebihan operator
Sekarang kita telah melihat perbandingan yang adil antara kode C ++ menggunakan operator overloading, dan kode yang sama di Jawa, kita sekarang dapat membahas "operator overloading" sebagai sebuah konsep.
Kelebihan operator sudah ada sejak sebelum komputer
Bahkan di luar ilmu komputer, ada operator overloading: Misalnya, dalam matematika, operator seperti
+
,-
,*
, dll kelebihan beban.Memang, signifikansi
+
,-
,*
, dll perubahan tergantung pada jenis dari operan (numeric, vektor, fungsi gelombang kuantum, matriks, dll).Sebagian besar dari kita, sebagai bagian dari program sains kami, belajar banyak signifikansi untuk operator, tergantung pada jenis operan. Apakah kita mendapati mereka membingungkan, mereka?
Kelebihan operator tergantung pada operannya
Ini adalah bagian terpenting dari kelebihan operator: Seperti dalam matematika, atau dalam fisika, operasi tergantung pada jenis operannya.
Jadi, ketahuilah jenis operan, dan Anda akan tahu efek operasinya.
Bahkan C dan Java memiliki operator (hard-code) overloading
Dalam C, perilaku nyata dari operator akan berubah sesuai dengan operannya. Misalnya, menambahkan dua bilangan bulat berbeda dari menambahkan dua ganda, atau bahkan satu bilangan bulat dan satu ganda. Bahkan ada domain aritmatika pointer keseluruhan (tanpa casting, Anda dapat menambahkan pointer ke integer, tetapi Anda tidak dapat menambahkan dua pointer ...).
Di Jawa, tidak ada pointer aritmatika, tetapi seseorang masih menemukan rangkaian string tanpa
+
operator akan cukup konyol untuk membenarkan pengecualian dalam kredo "operator kelebihan muatan jahat".Hanya saja Anda, sebagai kode C (karena alasan historis) atau Java (karena alasan pribadi , lihat di bawah), Anda tidak dapat menyediakan kode Anda sendiri.
Di C ++, kelebihan operator bukan opsional ...
Dalam C ++, overloading operator untuk tipe bawaan tidak dimungkinkan (dan ini adalah hal yang baik), tetapi tipe yang ditentukan pengguna dapat memiliki overload operator yang ditentukan pengguna .
Seperti yang sudah dikatakan sebelumnya, dalam C ++, dan sebaliknya ke Java, tipe pengguna tidak dianggap sebagai warga kelas dua bahasa, jika dibandingkan dengan tipe bawaan. Jadi, jika tipe bawaan memiliki operator, tipe pengguna harus dapat memilikinya juga.
Yang benar adalah bahwa, seperti
toString()
,clone()
,equals()
metode adalah untuk Java ( yaitu kuasi-standar-seperti ), C ++ operator overloading begitu banyak bagian dari C ++ sehingga menjadi sebagai alam sebagai operator C yang asli, atau sebelum metode Java disebutkan.Dikombinasikan dengan pemrograman template, overloading operator menjadi pola desain yang terkenal. Faktanya, Anda tidak bisa melangkah terlalu jauh di STL tanpa menggunakan operator yang kelebihan beban, dan operator yang kelebihan beban untuk kelas Anda sendiri.
... tapi jangan disalahgunakan
Overloading operator harus berusaha untuk menghormati semantik operator. Jangan kurangi dalam
+
operator (seperti dalam "jangan kurangi dalam suatuadd
fungsi", atau "kembalikan omong kosong dalam suatuclone
metode").Kelebihan beban pemain bisa sangat berbahaya karena dapat menyebabkan ambiguitas. Jadi mereka harus benar-benar dicadangkan untuk kasus-kasus yang terdefinisi dengan baik. Adapun
&&
dan||
, tidak pernah membebani mereka kecuali jika Anda benar-benar tahu apa yang Anda lakukan, karena Anda akan kehilangan evaluasi hubung singkat bahwa operator asli&&
dan||
menikmati.Jadi ... Ok ... Lalu mengapa tidak mungkin di Jawa?
Karena James Gosling berkata demikian:
Silakan bandingkan teks Gosling di atas dengan Stroustrup di bawah ini:
Apakah kelebihan beban operator menguntungkan Java?
Beberapa objek akan sangat diuntungkan dari kelebihan operator (jenis beton atau numerik, seperti BigDecimal, bilangan kompleks, matriks, wadah, iterator, pembanding, pengurai, dll.).
Dalam C ++, Anda bisa mendapat untung dari manfaat ini karena kerendahan hati Stroustrup. Di Jawa, Anda benar-benar kacau karena pilihan pribadi Gosling .
Bisakah itu ditambahkan ke Jawa?
Alasan untuk tidak menambah kelebihan operator sekarang di Jawa bisa menjadi perpaduan politik internal, alergi terhadap fitur, ketidakpercayaan pengembang (Anda tahu, penyabot yang tampaknya menghantui tim Java ...), kompatibilitas dengan JVM sebelumnya, waktu untuk menulis spesifikasi yang benar, dll.
Jadi jangan menahan nafas menunggu fitur ini ...
Tetapi mereka melakukannya dalam C # !!!
Ya...
Meskipun ini bukan satu-satunya perbedaan antara kedua bahasa, yang satu ini tidak pernah gagal untuk menghibur saya.
Rupanya, orang-orang C #, dengan "setiap primitif adalah a
struct
, danstruct
berasal dari Object" , melakukannya dengan benar pada percobaan pertama.Dan mereka melakukannya dalam bahasa lain !!!
Terlepas dari semua FUD terhadap kelebihan operator yang didefinisikan, bahasa berikut mendukungnya: Scala , Dart , Python , F # , C # , D , Algol 68 , Smalltalk , Groovy , Perl 6 , C ++, Ruby , Haskell , MATLAB , Eiffel , Lua , Clojure , Fortran 90 , Swift , Ada , Delphi 2005 ...
Begitu banyak bahasa, dengan begitu banyak filsafat yang berbeda (dan terkadang bertentangan), namun mereka semua sepakat tentang hal itu.
Bahan untuk dipikirkan...
sumber
James Gosling disamakan merancang Java sebagai berikut:
Anda dapat membaca konteks kutipan di sini
Pada dasarnya kelebihan operator sangat bagus untuk kelas yang memodelkan semacam titik, mata uang, atau angka kompleks. Tetapi setelah itu Anda mulai kehabisan contoh dengan cepat.
Faktor lain adalah penyalahgunaan fitur dalam C ++ oleh pengembang yang membebani operator seperti '&&', '||', operator pemain, dan tentu saja 'baru'. Kompleksitas yang dihasilkan dari menggabungkan ini dengan nilai by pass dan pengecualian tercakup dengan baik dalam C ++ Luar Biasa .
sumber
Many C++ design decisions have their roots in my dislike for forcing people to do things in some particular way [...] Often, I was tempted to outlaw a feature I personally disliked, I refrained from doing so because I did not think I had the right to force my views on others. (B. Stroustrup)
.I'd like them to go have a look at some C++ code out there that is hideously put together with weird hacks and "exceptional" features of the language
: Pemrogram yang buruk akan menulis kode yang buruk apa pun bahasanya. Hanya mencoba untuk meniru "pass-by-reference" untuk parameter fungsi di Jawa untuk memiliki ide. Saya telah melihat kode, dan tertawa sangat keras sampai sakit. Ini adalah jenis hal yang tidak digunakan Gosling, oleh karena itu, diperlukan peretasan yang mengerikan di Jawa, namun, ada secara asli, dengan biaya nol, baik di C # dan C ++.Lihat Boost.Units: tautan teks
Ini memberikan analisis Dimensi nol-overhead melalui overloading operator. Seberapa jelas ini bisa didapat?
akan benar-benar menampilkan "Energi = 4 J" yang benar.
sumber
Perancang Java memutuskan bahwa overloading operator lebih merepotkan daripada nilainya. Sederhana seperti itu.
Dalam bahasa di mana setiap variabel objek sebenarnya referensi, operator overloading mendapat bahaya tambahan menjadi sangat tidak logis - setidaknya untuk programmer C ++. Bandingkan situasi dengan operator C # == yang kelebihan beban dan
Object.Equals
danObject.ReferenceEquals
(atau apa pun namanya).sumber
Groovy memiliki operator kelebihan beban, dan berjalan di JVM. Jika Anda tidak keberatan hit kinerja (yang semakin kecil setiap hari). Otomatis berdasarkan nama metode. misalnya, '+' memanggil metode 'plus (argumen)'.
sumber
where ...
menjadi.Where(i => ...
). Kalau saja mereka melakukan hal yang sama dengan operator aritmatika, banyak hal akan lebih sederhana dan lebih kuat. Java memiliki keuntungan dari batu tulis yang bersih dan bisa mendapatkan ini dengan benar (meskipun untuk alasan keagamaan, mungkin tidak akan pernah).Saya pikir ini mungkin merupakan pilihan desain sadar untuk memaksa pengembang untuk membuat fungsi yang namanya dengan jelas mengomunikasikan niat mereka. Dalam C ++ pengembang akan membebani operator dengan fungsionalitas yang sering kali tidak memiliki hubungan dengan sifat yang diterima secara umum dari operator yang diberikan, sehingga hampir tidak mungkin untuk menentukan apa yang dilakukan sepotong kode tanpa melihat definisi operator.
sumber
In C++ developers would overload operators with functionality that would often have no relation to the commonly accepted nature of the given operator
: Ini adalah pernyataan serampangan. Saya seorang pengembang C ++ yang profesional sejak 12 tahun, dan saya jarang mengalami masalah ini. Bahkan, sebagian besar bug dan kesalahan desain yang saya lihat di C ++ ada dalam kode C-style (void *
, gips, dll.)add
fungsi tersebut dapat benar-benar disalahgunakan (seperti melakukan penggandaan, atau mendapatkan mutex) ... Penyalahgunaan yang disebutkan oleh user14128 tidak terbatas pada operator, tetapi ada semacam ketakutan patologis tentang kelebihan operator yang saya yakini berasal dari masa-masa awal C vs C ++, rasa takut yang tidak termodifikasi langsung ke Jawa, tapi untungnya, tidak masuk ke C # ... Pada akhirnya, menghormati semantik yang menghormati dan menulis fungsi / operator yang jelas adalah pekerjaan pengembang. Bukan bahasa.cout << f() || g();
kurung tidak membuatnya lebih jelas, mereka membuatnya benar. Dan jika operator bit shift tidak disalahgunakan, mereka tidak akan diperlukan. Kenapacout << (5&3) << endl;
lebih baik dari itucout.fmt(5&3)(endl);
? Menggunakan operator fungsi panggilan pada variabel anggota functor akan menjadi desain yang jauh lebih baik untuk stream daripada repurposing operator bitwise hanya karena mesin terbang terlihat bagus. Tapi ini jauh dari satu-satunya yang salah dengan aliran.Nah, Anda dapat benar-benar menembak diri sendiri dengan operator yang kelebihan beban. Ini seperti dengan pointer orang membuat kesalahan bodoh dengan mereka dan jadi diputuskan untuk mengambil gunting.
Setidaknya saya pikir itulah alasannya. Aku tetap di sisimu. :)
sumber
Beberapa orang mengatakan bahwa overloading operator di Jawa akan menyebabkan obsfuscation. Pernahkah orang-orang itu berhenti untuk melihat beberapa kode Java melakukan beberapa matematika dasar seperti meningkatkan nilai keuangan dengan persentase menggunakan BigDecimal? .... verbositas dari latihan semacam itu menjadi demonstrasi sendiri dari obsfuscation. Ironisnya, menambahkan overloading operator ke Jawa akan memungkinkan kami untuk membuat kelas Mata Uang kami sendiri yang akan membuat kode matematika seperti itu elegan dan sederhana (kurang usang).
sumber
Mengatakan bahwa operator kelebihan muatan mengarah ke kesalahan ketik logis dari operator yang tidak cocok dengan logika operasi, itu seperti mengatakan apa-apa. Jenis kesalahan yang sama akan terjadi jika nama fungsi tidak sesuai untuk logika operasi - jadi apa solusinya: jatuhkan kemampuan penggunaan fungsi !? Ini adalah jawaban yang lucu - "Tidak pantas untuk logika operasi", setiap nama parameter, setiap kelas, fungsi atau apa pun yang secara logika tidak pantas. Saya berpikir bahwa opsi ini harus tersedia dalam bahasa pemrograman yang terhormat, dan orang-orang yang berpikir itu tidak aman - hei, tidak ada yang bilang Anda harus menggunakannya. Mari kita ambil C #. Mereka menjatuhkan pointer tetapi hei - ada pernyataan 'kode tidak aman' - program yang Anda inginkan dengan risiko Anda sendiri.
sumber
Secara teknis, ada kelebihan operator di setiap bahasa pemrograman yang dapat menangani berbagai jenis angka, misalnya bilangan bulat dan bilangan real. Penjelasan: Istilah overloading berarti hanya ada beberapa implementasi untuk satu fungsi. Dalam sebagian besar bahasa pemrograman, implementasi yang berbeda disediakan untuk operator +, satu untuk bilangan bulat, satu untuk real, ini disebut operator overloading.
Sekarang, banyak orang merasa aneh bahwa Java memiliki operator kelebihan untuk operator + untuk menambahkan string bersama-sama, dan dari sudut pandang matematika ini memang aneh, tetapi dilihat dari sudut pandang pengembang bahasa pemrograman, tidak ada yang salah dengan menambahkan kelebihan operator bawaan untuk operator + untuk kelas lain mis. String. Namun, sebagian besar orang setuju bahwa sekali Anda menambahkan overin bawaan untuk + untuk String, maka umumnya merupakan ide bagus untuk menyediakan fungsionalitas ini untuk pengembang juga.
Sepenuhnya tidak setuju dengan kekeliruan yang berlebihan dari operator mengaburkan kode, karena hal ini dibiarkan oleh pengembang untuk memutuskan. Ini naif untuk berpikir, dan sejujurnya, sudah semakin tua.
+1 untuk menambahkan overloading operator di Java 8.
sumber
+
untuk menggabungkan string-ish apa pun adalah IMHO cukup mengerikan, seperti kelebihan beban/
dalam C dan FORTRAN untuk pembagian keseluruhan dan fraksional. Dalam banyak versi Pascal, penggunaan operator aritmatika pada jenis numerik apa pun akan menghasilkan hasil yang setara secara numerik dengan casting operanReal
, meskipun hasil yang mungkin bukan bilangan bulat harus dimasukkan melaluiTrunc
atauRound
sebelum mereka dapat ditugaskan ke bilangan bulat.Dengan asumsi Java sebagai bahasa implementasi maka a, b, dan c semuanya akan menjadi referensi untuk mengetik Complex dengan nilai awal nol. Juga dengan anggapan bahwa Kompleks tidak dapat diubah sebagai BigInteger yang disebutkan dan BigDecimal abadi yang serupa , saya pikir saya maksudkan yang berikut, karena Anda menetapkan referensi ke Kompleks yang dikembalikan dari menambahkan b dan c, dan tidak membandingkan referensi ini dengan a.
sumber
Terkadang akan menyenangkan untuk memiliki kelebihan operator, kelas teman dan banyak warisan.
Namun saya masih berpikir itu adalah keputusan yang bagus. Jika Java memiliki operator overloading maka kita tidak pernah bisa memastikan makna operator tanpa melihat melalui kode sumber. Saat ini itu tidak perlu. Dan saya pikir contoh Anda menggunakan metode bukan overloading operator juga cukup mudah dibaca. Jika Anda ingin memperjelas hal-hal Anda selalu dapat menambahkan komentar di atas pernyataan berbulu.
sumber
Ini bukan alasan yang baik untuk melarangnya, tetapi alasan praktis:
Orang tidak selalu menggunakannya secara bertanggung jawab. Lihat contoh ini dari scapy library Python:
Berikut penjelasannya:
sumber
Alternatif untuk Dukungan Asli Java Overloading Operator
Karena Java tidak memiliki kelebihan operator, berikut adalah beberapa alternatif yang dapat Anda perhatikan:
Jika ada yang mengetahui orang lain, silakan komentar, dan saya akan menambahkannya ke daftar ini.
sumber
Meskipun bahasa Java tidak secara langsung mendukung kelebihan operator, Anda dapat menggunakan plugin Manifold compiler di proyek Java apa saja untuk mengaktifkannya. Ini mendukung Java 8 - 13 (versi Java saat ini) dan didukung penuh di IntelliJ IDEA.
sumber