Mengapa di Jawa Anda dapat menambahkan Strings dengan operator +, ketika String adalah kelas? Dalam String.javakode saya tidak menemukan implementasi untuk operator ini. Apakah konsep ini melanggar orientasi objek?
Ini semua sihir kompiler. Anda tidak dapat melakukan overloading operator di Jawa.
Singa
18
Saya pikir yang aneh adalah bahwa String diimplementasikan sebagai perpustakaan di luar bahasa (di java.lang.String), namun ia memiliki dukungan khusus di dalam bahasa. Itu tidak benar.
@ 13ren Anda salah. String adalah bagian dari kelas java.lang yang merupakan singkatan dari bahasa - java lanaguage !!! Semua kelas dalam paket ini spesial. Perhatikan Anda tidak perlu mengimpor java.lang untuk menggunakannya.
Jawaban:
156
Mari kita lihat ekspresi sederhana berikut di Jawa
int x=15;String temp="x = "+x;
Compiler mengubahnya "x = "+x;menjadi StringBuilderinternal dan digunakan .append(int)untuk "menambahkan" integer ke string.
Jenis apa pun dapat dikonversi untuk mengetikkan String dengan konversi string.
Nilai x tipe T primitif pertama kali dikonversi ke nilai referensi seolah-olah dengan memberikannya sebagai argumen untuk ekspresi pembuatan instance kelas yang sesuai (§15.9):
Jika T adalah boolean, maka gunakan Boolean baru (x).
Jika T adalah karakter, maka gunakan Karakter baru (x).
Jika T adalah byte, pendek, atau int, maka gunakan Integer baru (x).
Jika T panjang, maka gunakan Long baru (x).
Jika T adalah float, maka gunakan Float baru (x).
Jika T ganda, maka gunakan Double baru (x).
Nilai referensi ini kemudian dikonversi ke tipe String oleh konversi string.
Sekarang hanya nilai referensi yang perlu dipertimbangkan:
Jika referensi adalah nol, itu dikonversi ke string "null" (empat karakter ASCII n, u, l, l).
Jika tidak, konversi dilakukan seolah-olah dengan doa metode toString objek yang direferensikan tanpa argumen; tetapi jika hasil dari memanggil metode toString adalah null, maka string "null" digunakan sebagai gantinya.
Metode toString didefinisikan oleh Object kelas primordial (§4.3.2). Banyak kelas menimpanya, terutama Boolean, Character, Integer, Long, Float, Double, dan String.
Optimalisasi Penggabungan String:
Suatu implementasi dapat memilih untuk melakukan konversi dan penggabungan dalam satu langkah untuk menghindari pembuatan dan kemudian membuang objek String perantara. Untuk meningkatkan kinerja penggabungan string berulang, kompiler Java dapat menggunakan kelas StringBuffer atau teknik serupa untuk mengurangi jumlah objek String menengah yang dibuat dengan mengevaluasi ekspresi.
Untuk tipe primitif, implementasi juga dapat mengoptimalkan pembuatan objek wrapper dengan mengonversi langsung dari tipe primitif ke string.
Versi yang dioptimalkan tidak akan benar-benar melakukan konversi String terbungkus penuh terlebih dahulu.
Ini adalah ilustrasi yang bagus dari versi yang dioptimalkan yang digunakan oleh kompiler, meskipun tanpa konversi yang primitif, di mana Anda dapat melihat kompiler mengubah hal-hal menjadi StringBuilder di latar belakang:
Melihat contoh di atas dan bagaimana kode byte berdasarkan kode sumber dalam contoh yang diberikan dihasilkan, Anda akan dapat melihat bahwa kompiler secara internal mengubah pernyataan berikut
cip+ciop;
ke
newStringBuilder(cip).append(ciop).toString();
Dengan kata lain, operator +dalam rangkaian string secara efektif merupakan singkatan untuk StringBuilderidiom yang lebih verbose .
Terima kasih banyak, saya tidak terbiasa dengan kode byte jvm tetapi menghasilkan kode untuk String plus = cip + ciop; dan String build = new StringBuilder (cip) .append (ciop) .toString (); sama. dan pertanyaan saya adalah apakah operasi ini melanggar orientasi objek?
Pooya
7
Tidak, tidak. Overloading operator (seperti dalam C ++ dan beberapa bahasa) memiliki beberapa kelemahan dan desainer Java merasa itu konsep yang agak membingungkan dan dihilangkan dari Jawa. Bagi saya, bahasa berorientasi objek harus memiliki konsep utama pewarisan, polimorfisme, dan enkapsulasi yang dimiliki Java.
Singa
2
ya, tapi saya pikir operator ini kelebihan beban untuk kelas String
Pooya
3
Ya, overloading operator digunakan di Jawa untuk penggabungan tipe String, namun Anda tidak dapat menentukan operator Anda sendiri (seperti dalam C ++, C # dan beberapa bahasa lainnya).
Singa
5
@Pooya: sebenarnya "int / int" vs. "int / float" sudah kelebihan operator, bahkan C pun memilikinya. Namun yang tidak dimiliki oleh C (dan Java) adalah overloading operator yang ditentukan pengguna: satu-satunya hal yang menentukan cara berbeda yang dapat digunakan operator (dalam C dan Java) adalah definisi bahasa (dan perbedaannya diterapkan dalam penyusun). C ++ berbeda karena memungkinkan overloading operator yang ditentukan pengguna (yang sering disebut sebagai "overloading operator").
Joachim Sauer
27
Ini adalah fitur kompiler Java yang memeriksa operan +operator. Dan berdasarkan operan itu menghasilkan kode byte:
Untuk String, ini menghasilkan kode ke string concat
Untuk Angka, ini menghasilkan kode untuk menambahkan angka.
Operator aditif memiliki prioritas yang sama dan secara asosiatif kiri asosiatif (mereka dikelompokkan dari kiri ke kanan). Jika jenis operan salah satu +operator adalah String, maka operasinya adalah penggabungan string.
Kalau tidak, tipe dari masing-masing operan +operator haruslah tipe yang dapat dikonversi (§5.1.8) menjadi tipe numerik primitif, atau kesalahan waktu kompilasi terjadi.
Dalam setiap kasus, tipe dari masing-masing operan dari -operator biner harus merupakan tipe yang dapat dikonversi (§5.1.8) menjadi tipe numerik primitif, atau kesalahan waktu kompilasi terjadi.
Kutipan dari spec sama sekali tidak relevan dengan pertanyaan ini.
Ernest Friedman-Hill
Ini adalah ekstrak "Jika jenis operan dari operator + adalah String, maka operasinya adalah penggabungan string. Jika tidak, tipe dari masing-masing operan dari operator + harus merupakan tipe yang dapat dikonversi (§5.1.8 ) ke tipe numerik primitif, atau kesalahan waktu kompilasi terjadi ". Bisakah Anda memberi tahu saya mengapa itu tidak relevan?
Ramesh PVK
7
Itu tidak mengatakan apa-apa tentang bagaimana itu diterapkan, yang merupakan pertanyaan. Saya pikir poster sudah mengerti bahwa fitur itu ada.
(2) Jika operan kiri adalah bilangan bulat maka itu akan dibongkar secara otomatis ke intdan kemudian aturan normal Jawa berlaku.
Marquis of Lorne
2
Dua aturan yang diberikan di bawah kutipan salah: Saya percaya mereka seharusnya: dua primitif (atau kelas unboxable) = penambahan; setidaknya satu string = rangkaian
mwfearnley
4
Bahasa Java menyediakan dukungan khusus untuk operator rangkaian string (+) dan untuk konversi objek lain ke string. Rangkaian string diimplementasikan melalui StringBuilder(atau StringBuffer) kelas dan appendmetodenya.
Arti +operator ketika diterapkan Stringdidefinisikan oleh bahasa, karena semua orang sudah menulis. Karena Anda tampaknya tidak menemukan ini cukup meyakinkan, pertimbangkan ini:
Ints, float dan doubles semuanya memiliki representasi biner yang berbeda, dan karenanya menambahkan dua int adalah operasi yang berbeda, dalam hal manipulasi bit, daripada menambahkan dua float: Untuk int Anda dapat menambahkan sedikit demi sedikit, membawa sedikit dan memeriksa luapan; untuk pelampung Anda harus berurusan dengan mantra dan eksponen secara terpisah.
Jadi, pada prinsipnya, "penambahan" tergantung pada sifat dari objek yang "ditambahkan". Java mendefinisikannya untuk String dan juga int dan float (longs, doubles, ...)
Jika ini masalahnya, apakah ada alasan mengapa StringBuilder ada untuk penggunaan umum? Apakah ada kasus di mana +operator tidak diganti oleh StringBuilder?
Cemre
2
Pertanyaan yang ingin Anda tanyakan adalah "mengapa operator + ada sama sekali untuk penggunaan umum?", Karena itulah kekejian di sini. Adapun pertanyaan Anda yang lain, saya tidak tahu persis, tapi saya kira tidak ada kasus seperti itu.
Scorpio
Compiler mungkin menggunakan concat () sebagai gantinya, jika hanya ada dua elemen. Compiler juga gagal untuk mengganti concat () dengan StringBuilder (atau menggunakan beberapa StringBuilders dan menambahkannya bersama-sama) ketika programmer membangun string dalam kode bersarang / loop panjang - menggunakan tunggal, StringBuilder eksplisit akan lebih baik untuk kinerja.
+
) adalah fitur bahasa Java.Jawaban:
Mari kita lihat ekspresi sederhana berikut di Jawa
Compiler mengubahnya
"x = "+x;
menjadiStringBuilder
internal dan digunakan.append(int)
untuk "menambahkan" integer ke string.5.1.11. Konversi string
15.18.1.
Versi yang dioptimalkan tidak akan benar-benar melakukan konversi String terbungkus penuh terlebih dahulu.
Ini adalah ilustrasi yang bagus dari versi yang dioptimalkan yang digunakan oleh kompiler, meskipun tanpa konversi yang primitif, di mana Anda dapat melihat kompiler mengubah hal-hal menjadi StringBuilder di latar belakang:
http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/
Kode java ini:
Hasilkan ini - lihat bagaimana kedua gaya gabungan mengarah ke bytecode yang sama:
Melihat contoh di atas dan bagaimana kode byte berdasarkan kode sumber dalam contoh yang diberikan dihasilkan, Anda akan dapat melihat bahwa kompiler secara internal mengubah pernyataan berikut
ke
Dengan kata lain, operator
+
dalam rangkaian string secara efektif merupakan singkatan untukStringBuilder
idiom yang lebih verbose .sumber
Ini adalah fitur kompiler Java yang memeriksa operan
+
operator. Dan berdasarkan operan itu menghasilkan kode byte:Inilah yang dikatakan oleh Java spec :
sumber
Tidak. Compiler melakukannya. Sebenarnya, kompiler membebani operator + berlebih untuk operan String.
sumber
Pertama-tama (+) kelebihan beban tidak diganti
Jika operan sisi kiri adalah String, ia berfungsi sebagai penggabungan.
Jika operan sisi kiri Integer berfungsi sebagai operator tambahan
sumber
int
dan kemudian aturan normal Jawa berlaku.Bahasa Java menyediakan dukungan khusus untuk operator rangkaian string (+) dan untuk konversi objek lain ke string. Rangkaian string diimplementasikan melalui
StringBuilder
(atauStringBuffer
) kelas danappend
metodenya.sumber
Arti
+
operator ketika diterapkanString
didefinisikan oleh bahasa, karena semua orang sudah menulis. Karena Anda tampaknya tidak menemukan ini cukup meyakinkan, pertimbangkan ini:Ints, float dan doubles semuanya memiliki representasi biner yang berbeda, dan karenanya menambahkan dua int adalah operasi yang berbeda, dalam hal manipulasi bit, daripada menambahkan dua float: Untuk int Anda dapat menambahkan sedikit demi sedikit, membawa sedikit dan memeriksa luapan; untuk pelampung Anda harus berurusan dengan mantra dan eksponen secara terpisah.
Jadi, pada prinsipnya, "penambahan" tergantung pada sifat dari objek yang "ditambahkan". Java mendefinisikannya untuk String dan juga int dan float (longs, doubles, ...)
sumber
The
+
Operator biasanya diganti denganStringBuilder
pada waktu kompilasi. Periksa jawaban ini untuk detail lebih lanjut tentang masalah ini.sumber
+
operator tidak diganti olehStringBuilder
?