Mengapa String tidak dapat diubah di Jawa?

177

Saya ditanya dalam sebuah wawancara mengapa String tidak bisa diubah

Saya menjawab seperti ini:

Ketika kita membuat string dalam java seperti String s1="hello";maka objek akan dibuat dalam string pool (halo) dan s1 akan menunjuk ke halo . Sekarang jika lagi kita lakukan String s2="hello";maka objek lain tidak akan dibuat tetapi s2 akan menunjuk ke hello karena JVM pertama akan memeriksa jika objek yang sama hadir dalam kumpulan string atau tidak. Jika tidak ada maka hanya yang baru yang dibuat tidak.

Sekarang jika java misalkan memungkinkan string bisa berubah maka jika kita mengubah s1 untuk hello worldkemudian s2 nilai juga akan hello worldjadi java String adalah kekal.

Bisakah ada yang memberi tahu saya jika jawaban saya benar atau salah ?

goyang
sumber
46
Kenapa selalu sulit dijawab. Jawaban yang paling benar mungkin: Karena para perancang bahasa menganggap itu adalah ide yang bagus.
Keppil
1
lihat juga, jawaban ini
3
Jawaban Anda tidak tepat sasaran. C ++ std::stringbisa berubah, tetapi mereka juga memiliki kumpulan string (well, lebih tepatnya, kumpulan array karakter).
Siyuan Ren
1
@rocking Sejujurnya, apakah itu benar atau tidak tergantung pada bagaimana mereka membacanya. Masalahnya, Java dapat memiliki kumpulan string karena string tidak berubah. Jika mereka memutuskan untuk membuat string bisa berubah maka mereka tidak akan menggunakan kumpulan string; jadi mungkin tidak akurat untuk mengatakan "string pool, oleh karena itu string tidak berubah"; itu lebih sebaliknya. The alasan untuk memilih string berubah diuraikan di bawah ini, dan string kolam renang adalah strategi kerja karena itu. Namun, jawaban Anda tidak salah , sepertinya tidak lengkap. Anda hanya harus menunggu dan melihat apa yang mereka katakan.
Jason C
34
Saya tidak mengerti mengapa pertanyaan ini ditutup. Jawaban terkait yang diharapkan bahkan bukan tentang Jawa dan tidak membahas subjek utama dari pertanyaan ini, yaitu "mengapa". Bagi saya ini kita salah satu kasus dari komunitas yang tidak bertanggung jawab yang bertindak atas pertanyaan yang tidak mereka ketahui. Saya telah menominasikannya untuk membuka kembali.
Edwin Dalorzo

Jawaban:

163

String tidak dapat diubah karena beberapa alasan, berikut ini ringkasannya:

  • Keamanan : parameter biasanya direpresentasikan sebagai Stringdalam koneksi jaringan, url koneksi basis data, nama pengguna / kata sandi dll. Jika itu bisa berubah, parameter ini dapat dengan mudah diubah.
  • Sinkronisasi dan konkurensi: membuat String tidak dapat diubah secara otomatis membuat mereka tetap aman sehingga menyelesaikan masalah sinkronisasi.
  • Caching : ketika kompiler mengoptimalkan objek String Anda, ia melihat bahwa jika dua objek memiliki nilai yang sama (a = "test", dan b = "test") dan dengan demikian Anda hanya perlu satu objek string (untuk a dan b, keduanya akan arahkan ke objek yang sama).
  • Pemuatan kelas : Stringdigunakan sebagai argumen untuk pemuatan kelas. Jika bisa berubah-ubah, ini bisa mengakibatkan kelas yang salah dimuat (karena objek yang bisa berubah mengubah statusnya).

Yang sedang berkata, kekekalan Stringhanya berarti Anda tidak dapat mengubahnya menggunakan API publiknya. Anda sebenarnya dapat mem-bypass API normal menggunakan refleksi. Lihat jawabannya di sini .

Dalam contoh Anda, jika Stringdapat diubah, pertimbangkan contoh berikut:

  String a="stack";
  System.out.println(a);//prints stack
  a.setValue("overflow");
  System.out.println(a);//if mutable it would print overflow
Komunitas
sumber
14
Bagaimana itu dapat mempengaruhi keamanan?
Archit Maheshwari
2
Bisakah seseorang menjelaskan pemuatan Kelas dengan sebuah contoh jika memungkinkan?
Viraj
6
Mengenai keamanan, jika saya tertarik untuk mengubah parameter koneksi, itu mudah saat dijalankan (dengan debugger, dll.). Mengenai pemuatan kelas, jika Stringdapat diubah, maka pemuat kelas akan mengambil string yang dilewati, membuat salinan, dan tidak mengubah salinannya. Ketika memikirkan masalah dengan sable yang java.lang.Stringdapat berubah , pikirkan bagaimana C ++ menyelesaikan masalah ini (karena std::strings dapat berubah .
Penebusan Terbatas
Mengenai keamanan, bagaimana string yang dapat diubah dapat diubah saat program sedang berjalan?
MasterJoe2
Karena String tidak dapat diubah, kode hash-nya di-cache pada saat pembuatan dan tidak perlu dihitung lagi.
Abdul Alim Shakir
45

Pengembang Java memutuskan bahwa String tidak dapat diubah karena aspek desain, efisiensi, dan keamanan berikut .

Design Strings dibuat di area memori khusus di tumpukan java yang dikenal sebagai "kolam String Intern". Saat Anda membuat String baru (Tidak dalam kasus menggunakan konstruktor String () atau fungsi String lainnya yang secara internal menggunakan konstruktor String () untuk membuat objek String baru; konstruktor String () selalu membuat konstanta string baru di pool kecuali kita panggil variabel metode intern () ) yang dicari kolam untuk memeriksa apakah sudah ada. Jika ada, maka kembali referensi objek String yang ada. Jika String tidak dapat diubah, mengubah String dengan satu referensi akan menghasilkan nilai yang salah untuk referensi lainnya.

Menurut artikel ini di DZone:

String Keamanan banyak digunakan sebagai parameter untuk banyak kelas java, mis. Koneksi jaringan, membuka file, dll. Jika String tidak dapat diubah, koneksi atau file akan diubah dan mengarah pada ancaman keamanan yang serius. String yang dapat berubah dapat menyebabkan masalah keamanan dalam Refleksi juga, karena parameternya adalah string.

Efisiensi Kode hash string sering digunakan di Jawa. Misalnya, dalam HashMap. Menjadi jaminan abadi bahwa kode hash akan selalu sama, sehingga bisa di-cache tanpa mengkhawatirkan perubahan. Itu berarti, tidak perlu menghitung kode hash setiap kali digunakan.

Alex Mathew
sumber
7
Pemahaman Anda tentang kumpulan string tidak benar. Konstanta string dibuat di pool internal, tetapi sangat mungkin untuk memiliki lebih dari satu objek string dengan teks yang sama. Saya setuju bahwa string yang tidak dapat diubah memungkinkan pengumpulan, tetapi tidak ada banyak kumpulan yang telah Anda nyatakan.
Jon Skeet
@ JonSkeet Anda benar. String s1 = String baru ("test"); pernyataan membuat konstanta string baru di kolam intern kecuali kita memanggil metode intern (). Terima kasih telah memperdalam pengetahuan saya tentang string intern pool.
Alex Mathew
2
Ini lebih dari sekadar menggunakan konstruktor string - hampir semua hal yang membuat string baru, misalnya substring, split, concat dll akan membuat string baru. Konstanta waktu kompilasi adalah kasus khusus di sini, bukan norma ...
Jon Skeet
@JonSkeet substring (), concat (), replace () dll secara internal menggunakan konstruktor String untuk membuat objek string baru. Terima kasih telah meningkatkan jawaban saya.
Alex Mathew
2
@ JonSkeet - Semua jawaban ini mengatakan bahwa imutabilitas meningkatkan "keamanan", tetapi jangan jelaskan caranya. Mereka semua terhubung ke artikel dzone yang tidak jelas yang juga tidak membantu. Jawaban / tautan tidak menjelaskan bagaimana string yang dapat diubah dapat diubah saat kode berjalan. Bisakah Anda jelaskan?
MasterJoe2
25

Kami tidak dapat memastikan apa yang sebenarnya dipikirkan oleh perancang Java saat mendesain, Stringtetapi kami hanya dapat menyimpulkan alasan-alasan ini berdasarkan keuntungan yang kami dapatkan dari kekekalan tali, Beberapa di antaranya adalah

1. Adanya String Constant Pool

Seperti yang dibahas dalam Mengapa String Disimpan dalam artikel String Constant Pool , setiap aplikasi membuat terlalu banyak objek string dan untuk menyelamatkan JVM dari pertama membuat banyak objek string dan kemudian mengumpulkan sampah mereka. JVM menyimpan semua objek string dalam area memori terpisah yang disebut String constant pool dan menggunakan kembali objek dari pool cache tersebut.

Setiap kali kita membuat string literal, JVM pertama kali melihat apakah literal itu sudah ada dalam kumpulan konstan atau tidak dan jika ada, referensi baru akan mulai menunjuk ke objek yang sama di SCP.

String a = "Naresh";
String b = "Naresh";
String c = "Naresh";

Dalam contoh di atas objek string dengan nilai Nareshakan bisa dibuat di SCP hanya sekali dan semua referensi a, b, cakan menunjuk ke objek yang sama tetapi bagaimana jika kita mencoba untuk membuat perubahan amisalnya a.replace("a", "").

Idealnya, aharus memiliki nilai Nreshtetapi b, charus tetap tidak berubah karena sebagai pengguna akhir kami hanya melakukan perubahan a. Dan kita tahu a, b, csemua yang menunjuk objek yang sama jadi jika kita membuat perubahan dalam a, orang lain juga harus mencerminkan perubahan.

Tetapi string immutability menyelamatkan kita dari skenario ini dan karena immutability objek string objek string Nareshtidak akan pernah berubah. Jadi, ketika kita membuat perubahan, abukannya mengubah objek string, NareshJVM membuat objek baru yang menetapkannya alalu membuat perubahan pada objek itu.

Jadi string pool hanya mungkin karena String tidak dapat diubah dan jika String tidak akan berubah, maka caching objek string dan menggunakannya kembali tidak akan memiliki kemungkinan karena variabel apa pun telah mengubah nilai dan merusak yang lain.

Dan itulah mengapa ditangani oleh JVM dengan sangat khusus dan telah diberikan area memori khusus.

2. Keamanan Thread

Objek disebut thread-safe ketika beberapa utas beroperasi di atasnya tetapi tidak satu pun dari mereka yang dapat merusak kondisinya dan objek memiliki status yang sama untuk setiap utas pada setiap titik waktu.

Karena kita objek yang tidak dapat diubah tidak dapat dimodifikasi oleh siapa pun setelah penciptaannya yang membuat setiap objek yang tidak dapat diubah adalah thread yang aman secara default. Kami tidak perlu menerapkan langkah-langkah keamanan ulir apa pun untuk itu seperti membuat metode yang disinkronkan.

Jadi karena objek string sifatnya yang tidak berubah dapat dibagikan oleh banyak utas dan bahkan jika ia dimanipulasi oleh banyak utas, ia tidak akan mengubah nilainya.

3. Keamanan

Di setiap aplikasi, kita perlu menyampaikan beberapa rahasia misalnya nama pengguna \ kata sandi, URL koneksi dan secara umum, semua informasi ini diteruskan sebagai objek string.

Sekarang anggaplah jika String tidak akan berubah di alam maka itu akan menyebabkan ancaman keamanan serius pada aplikasi karena nilai-nilai ini diperbolehkan untuk diubah dan jika diizinkan maka ini mungkin bisa berubah karena kode yang ditulis secara salah atau orang lain yang memiliki akses ke referensi variabel kami.

4. Memuat Kelas

Seperti yang dibahas dalam Membuat objek melalui Refleksi di Java dengan Contoh , kita bisa menggunakan Class.forName("class_name")metode untuk memuat kelas di memori yang lagi-lagi memanggil metode lain untuk melakukannya. Dan bahkan JVM menggunakan metode ini untuk memuat kelas.

Tetapi jika Anda melihat dengan jelas semua metode ini menerima nama kelas sebagai objek string sehingga Strings digunakan dalam pemuatan kelas java dan imutabilitas memberikan keamanan yang dapat dimasuki oleh kelas yang benar ClassLoader.

Misalkan jika String tidak akan berubah dan kami mencoba memuat java.lang.Objectyang bisa diubah org.theft.OurObjectdi antaranya dan sekarang semua objek kami memiliki perilaku yang dapat digunakan seseorang untuk hal-hal yang tidak diinginkan.

5. Cache HashCode

Jika kita akan melakukan operasi hashing apa pun pada objek apa pun, kita harus mengganti hashCode()metode tersebut dan mencoba menghasilkan kode hash yang akurat dengan menggunakan status objek. Jika keadaan objek semakin berubah yang berarti kode hashnya juga harus berubah.

Karena String tidak dapat diubah, maka nilai yang dipegang satu objek string tidak akan pernah berubah yang berarti kode hashnya juga tidak akan berubah yang memberikan kelas String peluang untuk melakukan cache kode hash-nya selama pembuatan objek.

Ya, objek String mem-cache kode hash-nya pada saat pembuatan objek yang menjadikannya kandidat terbaik untuk hashing operasi terkait karena kode hash tidak perlu dihitung lagi yang menghemat waktu kita. Inilah sebabnya mengapa String sebagian besar digunakan sebagai HashMapkunci.

Baca Lebih Lanjut tentang Mengapa String Tidak Berubah dan Final di Jawa .

Naresh Joshi
sumber
1
Mengenai Keamanan - Bagaimana nilai string yang dapat berubah dapat berubah dalam memori? Bagaimana orang lain dapat mengakses referensi variabel kami?
MasterJoe2
Ini bukan tentang bagaimana seseorang bisa mendapatkan akses ke referensi itu bagaimana jika seseorang memiliki akses ke sana? seperti yang disebutkan "jika String tidak akan berubah di alam maka itu akan menyebabkan ancaman keamanan serius pada aplikasi karena nilai-nilai ini diizinkan untuk diubah dan jika diizinkan maka ini mungkin bisa berubah karena kode yang ditulis secara salah atau orang lain yang memiliki akses ke referensi variabel kami. "
Naresh Joshi
Bagaimana pentingnya di sini. Entah mungkin untuk mendapatkan akses ke referensi atau tidak. Jika memungkinkan, dapatkah Anda menyebutkan 1-2 teknik *** (yaitu bagaimana) yang dapat digunakan untuk melakukannya? Jika tidak memungkinkan, maka poin tentang keamanan tidak berlaku. *** Contoh - Sebutkan satu teknik untuk menyerang DB aplikasi web -> SQL Injection. Apakah Anda tahu teknik seperti ini untuk menyerang referensi?
MasterJoe2
Sebagaimana disebutkan, "Itu bisa terjadi karena kode yang ditulis secara salah atau perubahan apa pun yang dilakukan oleh orang lain yang memiliki akses ke referensi variabel kami". misalkan Misalkan String bisa berubah dan Anda menulis beberapa metode yang menggunakan string rahasia string dan sekali lagi string itu diteruskan ke beberapa metode lain di antara dan salah satu metode tidak ditulis oleh Anda dan metode yang membuat beberapa perubahan ke dalam itu string sekarang setelah memanggil semua kontrol metode ini mengembalikan metode Anda dan Anda menggunakan string itu lagi tetapi telah diubah.
Naresh Joshi
2
Harap ungkapkan afiliasi apa pun dan jangan gunakan situs sebagai cara untuk mempromosikan situs Anda melalui posting. Lihat Bagaimana cara menulis jawaban yang baik? .
Yvette
21

Alasan terpenting menurut artikel ini di DZone:

String Constant Pool ... Jika string dapat diubah, mengubah string dengan satu referensi akan menghasilkan nilai yang salah untuk referensi lainnya.

Keamanan

String banyak digunakan sebagai parameter untuk banyak kelas java, misalnya koneksi jaringan, membuka file, dll. Jika String tidak dapat diubah, koneksi atau file akan berubah dan mengarah pada ancaman keamanan yang serius. ...

Semoga ini bisa membantu Anda.

JDGuide
sumber
@JasonC Saya hanya ingin tahu apakah jawaban saya salah atau tidak. Saya sudah menghadiri wawancara dan menunggu hasilnya. Jika jawaban mengatakan kepada mereka benar maka saya akan dipilih
goyang
1
Sesuai pengetahuan saya, jawaban Anda benar, tetapi tetap berarti referensi tidak akan pernah mengubah lokasi yang ditunjuk. Semua yang terbaik untuk wawancara Anda.
JDGuide
1
Jika menerima poin # 1 Anda, maka semua objek harus tidak berubah.
nicomp
Halo JDeveloper, saya mengedit jawaban Anda untuk memberikan atribusi yang tepat ke sumber jawaban Anda. Ingatlah untuk selalu menggunakan kutipan blokir untuk salinan konten kata demi kata. Terima kasih!
NickL
Artikel DZone berisi kesalahan besar tentang pengoperasian kumpulan Strign. Ini hanya untuk konstanta. Ergo alasan yang dinyatakan tidak valid.
Marquis of Lorne
4

Saya membaca posting ini Mengapa String Tidak Berubah atau Final di Jawa dan menganggap bahwa berikut ini mungkin alasan paling penting:

String tidak dapat diubah di Java karena objek String di- cache di kolam String . Karena cached String literal dibagikan di antara banyak klien selalu ada risiko, di mana tindakan satu klien akan mempengaruhi semua klien lain.

Tho
sumber
1

Kamu benar. Stringdalam java menggunakan konsep String Poolliteral. Ketika string dibuat dan jika string sudah ada di kumpulan, referensi dari string yang ada akan dikembalikan, alih-alih membuat objek baru dan mengembalikan referensi. Jika string tidak dapat diubah, mengubah string dengan satu referensi akan mengarah pada nilai yang salah untuk referensi lainnya.

Saya akan menambahkan satu hal lagi, karena Stringtidak dapat diubah, aman untuk multi threading dan sebuah instance String tunggal dapat dibagi di berbagai utas. Ini menghindari penggunaan sinkronisasi untuk keamanan utas, Strings secara implisit thread safe.

Akshay
sumber
0

Kelas string FINALartinya Anda tidak dapat membuat kelas apa pun untuk mewarisinya dan mengubah struktur dasar dan membuat Sting bisa berubah.

Variabel instance hal lain dan metode kelas String yang disediakan adalah sedemikian rupa sehingga Anda tidak dapat mengubah Stringobjek yang pernah dibuat.

Alasan apa yang Anda tambahkan tidak membuat String tidak berubah sama sekali. Ini semua mengatakan bagaimana String disimpan di heap. Juga kumpulan string membuat perbedaan besar dalam kinerja

Tendangan
sumber
11
Jika kelas dinyatakan sebagai final, itu berarti bahwa kelas tidak dapat diwarisi, tetapi itu tidak berarti bahwa bidang instance kelas tidak dapat diubah sehingga kelas tidak dapat diubah.
Dmitry Bychenko
@Zeeshan: Kelas contoh yang Anda berikan semuanya tidak berubah.
Siyuan Ren
0

String diberikan sebagai tidak dapat diubah oleh sistem mikro Sun, karena string dapat digunakan untuk menyimpan sebagai kunci dalam koleksi peta. StringBuffer bisa berubah. Itulah alasannya, itu tidak bisa digunakan sebagai kunci dalam objek peta

chaithanya krishna gogineni
sumber
0

Alasan paling penting dari suatu String yang dibuat tidak berubah di Jawa adalah pertimbangan Keamanan . Selanjutnya adalah Caching .

Saya percaya alasan lain yang diberikan di sini, seperti efisiensi, konkurensi, desain, dan kumpulan string mengikuti dari fakta bahwa String in dibuat abadi. Untuk misalnya. String Pool dapat dibuat karena String tidak dapat diubah dan bukan sebaliknya.

Periksa transkrip wawancara Gosling di sini

Dari sudut pandang strategis, mereka cenderung lebih sering bebas masalah. Dan biasanya ada hal-hal yang dapat Anda lakukan dengan immutables yang tidak dapat Anda lakukan dengan hal-hal yang bisa berubah, seperti cache hasilnya. Jika Anda meneruskan string ke metode buka file, atau jika Anda meneruskan string ke konstruktor untuk label di antarmuka pengguna, di beberapa API (seperti di banyak Windows API), Anda meneruskan array karakter. Penerima objek itu benar-benar harus menyalinnya, karena mereka tidak tahu apa-apa tentang masa penyimpanannya. Dan mereka tidak tahu apa yang terjadi pada objek, apakah itu sedang diubah di bawah kaki mereka.

Anda akhirnya hampir dipaksa untuk mereplikasi objek karena Anda tidak tahu apakah Anda bisa memilikinya atau tidak. Dan salah satu hal yang menyenangkan tentang objek yang tidak dapat diubah adalah jawabannya adalah, "Ya, tentu saja Anda tahu." Karena masalah kepemilikan, siapa yang berhak mengubahnya, tidak ada.

Salah satu hal yang memaksa Strings tidak berubah adalah keamanan. Anda memiliki metode buka file. Anda melewatkan sebuah String ke sana. Dan kemudian melakukan semua jenis pemeriksaan otentikasi sebelum sempat melakukan panggilan OS. Jika Anda berhasil melakukan sesuatu yang secara efektif mengubah String, setelah pemeriksaan keamanan dan sebelum panggilan OS, maka boom, Anda masuk. Tapi String tidak dapat diubah, sehingga serangan semacam itu tidak bekerja. Contoh tepat itulah yang benar-benar menuntut agar String tidak berubah

Sameer Sinha
sumber
0

Selain jawaban yang bagus, saya ingin menambahkan beberapa poin. Seperti Strings, Array memegang referensi ke awal array jadi jika Anda membuat dua array arr1dan arr2melakukan sesuatu seperti arr2 = arr1ini akan membuat referensi yang arr2sama arr1karena dengan mengubah nilai pada salah satu dari mereka akan menghasilkan perubahan yang lain misalnya

public class Main {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4};
        int[] b = a;
        a[0] = 8;
        b[1] = 7;
        System.out.println("A: " + a[0] + ", B: " + b[0]);
        System.out.println("A: " + a[1] + ", B: " + b[1]);
        //outputs
        //A: 8, B: 8
        //A: 7, B: 7
    }
}

Tidak hanya itu akan menyebabkan bug dalam kode itu juga dapat (dan akan) dieksploitasi oleh pengguna jahat. Misalkan jika Anda memiliki sistem yang mengubah kata sandi admin. Pengguna harus terlebih dahulu memasukkan newPassworddan kemudian oldPasswordjika oldPasswordsama adminPassdengan program mengganti kata sandi adminPass = newPassword. katakanlah kata sandi baru memiliki referensi yang sama dengan kata sandi admin sehingga programmer yang buruk dapat membuat tempvariabel untuk menahan kata sandi admin sebelum pengguna memasukkan data jika oldPasswordsama dengan tempitu mengubah kata sandi sebaliknyaadminPass = temp. Seseorang yang mengetahui bahwa dengan mudah dapat memasukkan kata sandi baru dan tidak pernah memasukkan kata sandi lama dan abracadabra ia memiliki akses admin. Hal lain yang saya tidak mengerti ketika belajar tentang Strings mengapa JVM tidak membuat string baru untuk setiap objek dan memiliki tempat yang unik dalam memori untuk itu dan Anda bisa melakukannya menggunakan new String("str");Alasan Anda tidak ingin selalu menggunakan newadalah karena ini tidak efisien dalam memori dan lebih lambat dalam banyak kasus, baca lebih lanjut .

Qeaxe
sumber
0

Jika HELLOadalah Anda String maka Anda tidak dapat mengubah HELLOke HILLO. Properti ini disebut properti kekekalan.

Anda dapat memiliki beberapa variabel String penunjuk ke titik String HELLO.

Tetapi jika HELLO adalah char Array maka Anda dapat mengubah HELLO menjadi HILLO. Misalnya,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

Menjawab:

Bahasa pemrograman memiliki variabel data yang tidak berubah sehingga dapat digunakan sebagai kunci dalam pasangan nilai. Variabel string digunakan sebagai kunci / indeks, sehingga tidak dapat diubah .

Uddhav Gautam
sumber
-1

Dari Securitysudut pandang kita dapat menggunakan contoh praktis ini:

DBCursor makeConnection(String IP,String PORT,String USER,String PASS,String TABLE) {

    // if strings were mutable IP,PORT,USER,PASS can be changed by validate function
    Boolean validated = validate(IP,PORT,USER,PASS);

    // here we are not sure if IP, PORT, USER, PASS changed or not ??
    if (validated) {
         DBConnection conn = doConnection(IP,PORT,USER,PASS);
    }

    // rest of the code goes here ....
}
darxtrix
sumber