Mengapa String tidak dapat diubah di Java?

1. Perkenalan

Di Java, Strings tidak dapat diubah. Sebuah pertanyaan jelas yang cukup umum dalam wawancara adalah "Mengapa String dirancang sebagai tidak dapat diubah di Jawa?"

James Gosling, pencipta Java, pernah ditanyai dalam sebuah wawancara kapan seseorang harus menggunakan immutables, yang dia jawab:

Saya akan menggunakan immutable kapan pun saya bisa.

Dia lebih jauh mendukung argumennya yang menyatakan fitur-fitur yang disediakan keabadian, seperti caching, keamanan, penggunaan kembali yang mudah tanpa replikasi, dll.

Dalam tutorial ini, kita akan mempelajari lebih lanjut mengapa desainer bahasa Java memutuskan untuk menjaga String tetap tidak berubah.

2. Apa Itu Objek yang Tidak Berubah?

Objek yang tidak dapat diubah adalah objek yang keadaan internalnya tetap konstan setelah seluruhnya dibuat . Ini berarti bahwa setelah objek telah ditetapkan ke variabel, kita tidak dapat memperbarui referensi atau mengubah status internal dengan cara apa pun.

Kami memiliki artikel terpisah yang membahas objek yang tidak dapat diubah secara detail. Untuk informasi selengkapnya, baca artikel Objek yang Tidak Dapat Diubah di Java.

3. Mengapa String Tidak Berubah di Java?

Manfaat utama dari menjaga agar kelas ini tetap tidak dapat diubah adalah penyimpanan cache, keamanan, sinkronisasi, dan kinerja.

Mari kita bahas bagaimana hal ini bekerja.

3.1. Perkenalkan ke String Pool

The String adalah struktur data yang paling banyak digunakan. Menyimpan literal String dan menggunakannya kembali menghemat banyak ruang heap karena variabel String yang berbeda merujuk ke objek yang sama di kumpulan String . Kolam intern string melayani tujuan ini dengan tepat.

Java String Pool adalah area memori khusus tempat Strings disimpan oleh JVM . Karena Strings tidak dapat diubah di Java, JVM mengoptimalkan jumlah memori yang dialokasikan untuknya dengan hanya menyimpan satu salinan dari setiap String literal di pool. Proses ini disebut interning:

String s1 = "Hello World"; String s2 = "Hello World"; assertThat(s1 == s2).isTrue();

Karena keberadaan kumpulan String dalam contoh sebelumnya, dua variabel berbeda menunjuk ke objek String yang sama dari kumpulan, sehingga menghemat sumber daya memori yang penting.

Kami memiliki artikel terpisah yang didedikasikan untuk Java String Pool. Untuk informasi lebih lanjut, baca artikel itu.

3.2. Keamanan

The String banyak digunakan dalam aplikasi Java untuk menyimpan potongan sensitif informasi seperti username, password, URL koneksi, koneksi jaringan, dll Ini juga digunakan secara luas oleh kelas loader JVM sementara kelas pemuatan.

Oleh karena itu, mengamankan kelas String sangat penting terkait keamanan seluruh aplikasi secara umum. Misalnya, pertimbangkan cuplikan kode sederhana ini:

void criticalMethod(String userName) { // perform security checks if (!isAlphaNumeric(userName)) { throw new SecurityException(); } // do some secondary tasks initializeDatabase(); // critical task connection.executeUpdate("UPDATE Customers SET Status = 'Active' " + " WHERE UserName = '" + userName + "'"); }

Dalam potongan kode di atas, katakanlah kita menerima objek String dari sumber yang tidak dapat dipercaya. Kami melakukan semua pemeriksaan keamanan yang diperlukan pada awalnya untuk memeriksa apakah String hanya alfanumerik, diikuti oleh beberapa operasi lainnya.

Ingatlah bahwa metode pemanggil sumber kami yang tidak dapat diandalkan masih memiliki referensi ke objek userName ini .

Jika Strings bisa berubah, maka pada saat kami menjalankan pembaruan, kami tidak dapat memastikan bahwa String yang kami terima, bahkan setelah melakukan pemeriksaan keamanan, akan aman. Metode pemanggil yang tidak dapat dipercaya masih memiliki referensi dan dapat mengubah String di antara pemeriksaan integritas. Sehingga membuat kueri kami rentan terhadap injeksi SQL dalam kasus ini. Jadi, Strings yang dapat berubah dapat menyebabkan degradasi keamanan seiring waktu.

Bisa juga terjadi bahwa String userName terlihat oleh thread lain, yang kemudian dapat mengubah nilainya setelah pemeriksaan integritas.

Secara umum, kekekalan datang untuk menyelamatkan kami dalam kasus ini karena lebih mudah untuk beroperasi dengan kode sensitif ketika nilai tidak berubah karena ada lebih sedikit interleavings operasi yang mungkin mempengaruhi hasil.

3.3. Sinkronisasi

Menjadi tidak dapat diubah secara otomatis membuat utas String aman karena tidak akan diubah saat diakses dari banyak utas.

Karenanya , objek yang tidak dapat diubah, secara umum, dapat dibagikan di beberapa utas yang berjalan secara bersamaan. Mereka juga aman untuk thread karena jika sebuah thread mengubah nilainya, alih-alih mengubahnya, String baru akan dibuat di kolam String . Karenanya, Strings aman untuk multi-threading.

3.4. Caching Hashcode

Karena objek String banyak digunakan sebagai struktur data, mereka juga banyak digunakan dalam implementasi hash seperti HashMap , HashTable , HashSet , dll. Saat beroperasi pada implementasi hash ini, metode hashCode () sering dipanggil untuk pengelompokan.

Keabadian menjamin Strings bahwa nilainya tidak akan berubah. Jadi metode hashCode () diganti dalam kelas String untuk memfasilitasi caching, sehingga hash dihitung dan di-cache selama panggilan hashCode () pertama dan nilai yang sama dikembalikan sejak saat itu.

Ini, pada gilirannya, meningkatkan kinerja koleksi yang menggunakan implementasi hash saat dioperasikan dengan objek String .

Di sisi lain, String yang bisa berubah akan menghasilkan dua kode hash yang berbeda pada saat penyisipan dan pengambilan jika konten String diubah setelah operasi, berpotensi kehilangan objek nilai di Peta .

3.5. Performa

Seperti yang kita lihat sebelumnya, kumpulan String ada karena String tidak dapat diubah. Pada gilirannya, ini meningkatkan kinerja dengan menghemat memori heap dan akses yang lebih cepat dari implementasi hash saat dioperasikan dengan Strings.

Karena String adalah struktur data yang paling banyak digunakan, peningkatan kinerja String memiliki pengaruh yang besar pada peningkatan kinerja aplikasi secara keseluruhan.

4. Kesimpulan

Melalui artikel ini, kita dapat menyimpulkan bahwa String tidak dapat diubah dengan tepat sehingga referensinya dapat diperlakukan sebagai variabel normal dan seseorang dapat meneruskannya, di antara metode dan di seluruh utas, tanpa mengkhawatirkan apakah objek String yang sebenarnya ditunjuk akan berubah.

Kami juga mempelajari apa yang mungkin menjadi alasan lain yang mendorong desainer bahasa Java untuk menjadikan kelas ini sebagai tidak dapat diubah.