String
tidak dapat diubah * tetapi ini hanya berarti Anda tidak dapat mengubahnya menggunakan API publiknya.
Apa yang Anda lakukan di sini adalah menghindari API normal, menggunakan refleksi. Dengan cara yang sama, Anda dapat mengubah nilai enum, mengubah tabel pencarian yang digunakan dalam bilangan bulat Integer dll.
Sekarang, alasan s1
dan s2
nilai perubahan, adalah bahwa keduanya merujuk ke string yang diinternir yang sama. Kompiler melakukan ini (sebagaimana disebutkan oleh jawaban lain).
Alasannya s3
sebenarnya tidak sedikit mengejutkan bagi saya, karena saya pikir itu akan berbagi value
array ( itu dalam versi Java yang lebih lama , sebelum Java 7u6). Namun, melihat kode sumber String
, kita dapat melihat bahwa value
array karakter untuk substring sebenarnya disalin (menggunakan Arrays.copyOfRange(..)
). Inilah mengapa itu tidak berubah.
Anda dapat menginstal SecurityManager
, untuk menghindari kode berbahaya untuk melakukan hal-hal seperti itu. Tetapi perlu diingat bahwa beberapa perpustakaan bergantung pada penggunaan trik-trik refleksi semacam ini (biasanya alat ORM, perpustakaan AOP dll).
*) Saya awalnya menulis bahwa String
s tidak benar-benar abadi, hanya "tidak dapat diubah". Ini mungkin menyesatkan dalam implementasi saat ini String
, di mana value
array memang ditandai private final
. Namun, masih perlu dicatat bahwa tidak ada cara untuk mendeklarasikan array di Java sebagai tidak dapat diubah, jadi harus berhati-hati untuk tidak mengeksposnya di luar kelasnya, bahkan dengan pengubah akses yang tepat.
Karena topik ini tampaknya sangat populer, inilah beberapa saran untuk bacaan lebih lanjut: Refleksi Madness Heinz Kabutz dari JavaZone 2009, yang mencakup banyak masalah di OP, bersama dengan refleksi lain ... well ... kegilaan.
Ini mencakup mengapa ini kadang berguna. Dan mengapa, sebagian besar waktu, Anda harus menghindarinya. :-)