Mari kita pertimbangkan pertanyaan tentang string di Java: perbedaan antara "ABC" + '/' dan "ABC" + "/". Melalui contoh ini, kita dapat mempraktikkan penggunaan javap dalam alat JDK. Pertanyaan aslinya adalah sebagai berikut:
Apa perbedaan antara mengobati slash/sebagai karakter atau string?
Satu digunakan sebagai char tipe data dasar, dan yang lainnya adalah string objek. Apa perbedaan spesifiknya?
Apakah akan lebih efisien untuk memperlakukannya sebagai karakter?
String str = "abc" + '/';
Dan
String str = "abc" + "/";
1. Optimalisasi Kompiler
Pertama -tama, Anda harus tahu bahwa dua kalimat di atas memiliki efek yang sama, karena kompiler akan mengoptimalkan dua kalimat di atas ke yang berikut:
String str = "abc/";
Kami dapat membuktikan ini melalui JAVAP. Untuk Javap, kita dapat merujuk pada "5 alat JDK yang harus diketahui oleh setiap pengembang Java". Kami pertama -tama membuat kelas: StringOne, dan mengisi kode berikut dalam metode utama:
StringOne.javastring str1 = "abc" + '/'; string str2 = "abc" + "/";system.out.println(str1 == str2);
Kompilasi dan jalankan, hasil output benar. Selanjutnya, JAVAP kami diluncurkan, masukkan perintah berikut di baris perintah:
javap -v -l stringone.class> stringone.s
Kemudian periksa file StringOne.s yang dihasilkan. Anda akan menemukan bahwa ada beberapa baris di dalamnya
StringOne.S #2 = String #20 // ABC /...# 20 = UTF8 ABC/... 0: LDC #2 // String ABC/2: STORE_13: LDC #2 // String ABC/5: STORE_2
Penjelasan: STR1 dan STR2 keduanya merujuk pada string "ABC/".
2. Gunakan javap untuk menganalisis perbedaan
Sekarang mari kita ubah pertanyaannya. Apa perbedaan antara metode StringAddstring dan StringAddchar dalam kode berikut?
StringTWoPublic Static String StringAddString (String str1, String str2) {return str1 + str2;} public static String stringAddChar (string str, char ch) {return str + ch;}Kali ini, JAVAP digunakan untuk dekompilasi, dan beberapa isi file yang dihasilkan adalah sebagai berikut
Stringtwo.spublic java.lang.string stringaddString (java.lang.string, java.lang.string); deskriptor: (ljava/lang/string; ljava/lang/string;) ljava/lang/string; Bendera: Kode ACC_PUBLIC: Stack = 2, penduduk setempat = 3, args_size = 3 0: baru #2 // kelas java/lang/stringbuilder 3: dup 4: Invokespecial #3 // Metode Java/Lang/StringBuilder. "<inin>" ":") v 7: aload_1 8: string. append: (ljava/lang/string;) ljava/lang/stringbuilder; 11: Aload_2 12: Invokevirtual #4 // Metode Java/Lang/StringBuilder. append: (ljava/lang/string;) ljava/lang/stringbuilder; 15: Invokevirtual #5 // Metode Java/Lang/StringBuilder. tostring :() ljava/lang/string; 18: areturnpublic java.lang.string stringaddchar (java.lang.string, char); deskriptor: (ljava/lang/string; c) ljava/lang/string; flags: ACC_PUBLIC Code: stack=2, locals=3, args_size=3 0: new #2 // class java/lang/StringBuilder 3: dup 4: invokespecial #3 // Method java/lang/StringBuilder."<init>":()V 7: aload_1 8: invokevirtual #4 // Method java/lang/stringbuilder.append: (ljava/lang/string;) ljava/lang/stringBuilder; 11: iload_2 12: Invokevirtual #6 // Metode java/lang/stringbuilder.append: (c) ljava/lang/stringbuilder; 15: Invokevirtual #5 // Metode Java/Lang/StringBuilder.tostring :() ljava/lang/string; 18: Areturn
Sekarang, kita dapat dengan jelas melihat proses melaksanakan kedua metode ini:
StringAddstring
Prosedur StringAddChar sama dengan StringAddString, kecuali bahwa ketika metode append disebut kedua kalinya, parameter StringAddstring adalah tipe string, sedangkan parameter StringAddchar adalah tipe char.
3. Metode append (char) dan append (string) Metode Kelas StringBuilder
Di sini, kita hanya perlu memeriksa kode sumber secara langsung (tambang adalah kode sumber yang dilengkapi dengan JDK1.8.0_60). Perhatikan bahwa meskipun dokumen menunjukkan bahwa StringBuilder mewarisi dari objek, dari kode sumber, itu diwarisi dari kelas abstrak AbstractStringBuilder. Dan metode append diimplementasikan oleh AbstractStringBuilder.
AbstractStringBuilder.java
public abstractStringBuilder append (char c) {ensurecapacityinternal (count + 1); // Pastikan bahwa array dapat mengakomodasi nilai penghitungan+1 karakter [Count ++] = C; kembalikan ini;} public abstractStringBuilder append (string str) {if (str == null) return appendNull (); int len = str.length (); Ensurecapacityinternal (Count + Len); str.getchars (0, len, nilai, hitungan); // Salin array karakter dalam string ke dalam array karakter objek ini Count += len; kembalikan ini;}Sisanya tidak akan diposting lagi. String.getChars (int, int, char [], int) pada akhirnya tergantung pada arraycopy void asli statis publik (objek, int, objek, int, int). Dengan kata lain, dapat ditulis dalam bahasa C, dan efisiensinya harus lebih baik ketika menyalin array besar daripada program yang ditulis dalam Java. Jadi, sekarang izinkan saya memberi tahu Anda apa yang saya mengerti:
Dalam hal memori langsung, karena string berisi array char, array harus memiliki bidang panjang. Pada saat yang sama, kelas string memiliki properti int hash, dan objek itu sendiri akan menempati memori tambahan untuk menyimpan informasi lain, sehingga string akan menempati lebih banyak memori. Namun, jika string sangat panjang, maka overhead memori ini hampir dapat diabaikan; Dan jika string itu (sangat) pendek, sangat mungkin ada banyak referensi bersama untuk berbagi overhead memori ini, sehingga kelebihan overhead memori masih dapat diabaikan.
Dari tumpukan panggilan, karena string hanya memiliki satu atau dua panggilan fungsi lebih dari char di sini, jika fungsi overhead panggilan (termasuk ruang dan ruang) tidak dipertimbangkan, itu harus serupa; Jika fungsi overhead panggilan dipertimbangkan, "ABC" + '/' harus lebih baik; Tetapi ketika beberapa karakter perlu dihubungkan (saya pikir situasi ini harus lebih umum, bukan?), Karena menggunakan char membutuhkan banyak loop untuk menyelesaikan koneksi, jumlah fungsi yang disebut hanya akan lebih dipanggil daripada menggunakan string. Pada saat yang sama, menyalin tidak akan lebih cepat dari string secara langsung menyalin array. Jadi saat ini, itu menjadi "ABC" + "/" dengan throughput yang lebih besar.
Sekarang saya merasa pertanyaan ini ditanyakan: apakah lebih efisien menggunakan panggilan sistem saat membaca dan menulis file, atau lebih efisien untuk menggunakan pustaka IO di pustaka fungsi standar. Saya pribadi merasa bahwa meskipun perpustakaan IO standar harus memanggil panggilan sistem pada akhirnya, dan beberapa variabel sementara dan tumpukan panggilan yang lebih dalam akan dihasilkan, karena mekanisme buffering perpustakaan IO, throughput perpustakaan IO akan lebih besar, dan kinerja real-time dari panggilan sistem akan lebih baik. Demikian pula, meskipun kelas string akan memiliki lebih banyak bidang dan tumpukan fungsi yang lebih dalam, throughput harus lebih baik karena cache dan lebih banyak penyalinan langsung.
Pertanyaan baru
Dilihat dari kode dekompilasi JavaP di atas, ketika kedua string ditambahkan bersama -sama, mereka akan menjadi string menambahkan di StringBuilder. Jadi, secara teori, kode manakah yang lebih efisien?
String str1 = "ABC" + "123"; // 1StringBuilder StringBuilder = new StringBuilder (); // 2StringBuilder.Append ("ABC"); StringBuilder.Append ("123"); String str2 = StringBuilder.ToString ();Biarkan pertanyaan ini harus dipikirkan semua orang!
Di atas adalah semua konten artikel ini, yang membantu Anda membedakan String+String+Char dengan lebih baik di Java. Saya berharap ini akan membantu untuk pembelajaran semua orang.