Mengapa di Jawa Anda dapat menambahkan Strings dengan operator +, ketika String adalah kelas? Dalam String.java
kode saya tidak menemukan implementasi untuk operator ini. Apakah konsep ini melanggar orientasi objek?
Mengapa di Jawa Anda dapat menambahkan Strings dengan operator +, ketika String adalah kelas? Dalam String.java
kode saya tidak menemukan implementasi untuk operator ini. Apakah konsep ini melanggar orientasi objek?
Jawaban:
Mari kita lihat ekspresi sederhana berikut di Jawa
int x=15;
String temp="x = "+x;
Compiler mengubahnya "x = "+x;
menjadi StringBuilder
internal 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.
Lihat §5.4 untuk detail konteks konversi 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:
http://caprazzi.net/posts/java-bytecode-string-concatenation-and-stringbuilder/
Kode java ini:
public static void main(String[] args) {
String cip = "cip";
String ciop = "ciop";
String plus = cip + ciop;
String build = new StringBuilder(cip).append(ciop).toString();
}
Hasilkan ini - lihat bagaimana kedua gaya gabungan mengarah ke bytecode yang sama:
L0
LINENUMBER 23 L0
LDC "cip"
ASTORE 1
L1
LINENUMBER 24 L1
LDC "ciop"
ASTORE 2
// cip + ciop
L2
LINENUMBER 25 L2
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESTATIC java/lang/String.valueOf(Ljava/lang/Object;)Ljava/lang/String;
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 3
// new StringBuilder(cip).append(ciop).toString()
L3
LINENUMBER 26 L3
NEW java/lang/StringBuilder
DUP
ALOAD 1
INVOKESPECIAL java/lang/StringBuilder.<init>(Ljava/lang/String;)V
ALOAD 2
INVOKEVIRTUAL java/lang/StringBuilder.append(Ljava/lang/String;)Ljava/lang/StringBuilder;
INVOKEVIRTUAL java/lang/StringBuilder.toString()Ljava/lang/String;
ASTORE 4
L4
LINENUMBER 27 L4
RETURN
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
new StringBuilder(cip).append(ciop).toString();
Dengan kata lain, operator +
dalam rangkaian string secara efektif merupakan singkatan untuk StringBuilder
idiom yang lebih verbose .
Ini adalah fitur kompiler Java yang memeriksa operan +
operator. Dan berdasarkan operan itu menghasilkan kode byte:
Inilah yang dikatakan oleh Java spec :
Operator + dan
-
disebut operator aditif. AdditiveExpression: MultiplicativeExpression AdditiveExpression + MultiplicativeExpression AdditiveExpression - MultiplicativeExpressionOperator aditif memiliki prioritas yang sama dan secara asosiatif kiri asosiatif (mereka dikelompokkan dari kiri ke kanan). Jika jenis operan salah satu
+
operator adalahString
, 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.
Bagaimana kelas String menimpa + operator?
Tidak. Compiler melakukannya. Sebenarnya, kompiler membebani operator + berlebih untuk operan String.
Pertama-tama (+) kelebihan beban tidak diganti
Bahasa Java menyediakan dukungan khusus untuk operator rangkaian string (+), yang telah kelebihan beban untuk objek Java Strings.
Jika operan sisi kiri adalah String, ia berfungsi sebagai penggabungan.
Jika operan sisi kiri Integer berfungsi sebagai operator tambahan
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
(atau StringBuffer
) kelas dan append
metodenya.
Arti +
operator ketika diterapkan String
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, ...)
The +
Operator biasanya diganti dengan StringBuilder
pada waktu kompilasi. Periksa jawaban ini untuk detail lebih lanjut tentang masalah ini.
+
operator tidak diganti oleh StringBuilder
?
+
) adalah fitur bahasa Java.