Mengapa string tidak dapat diubah dalam beberapa bahasa?

9

String adalah kelas yang tidak dapat diubah di Jawa. Kelas yang tidak berubah hanyalah kelas yang instansnya tidak dapat dimodifikasi. Mengapa bahasa pemrograman Java memilih untuk membuat objek String kelas tidak berubah?

Tupledev
sumber
2
@ PJTraill Sepertinya tidak bisa dihindari sama sekali. Literal string dalam bahasa lain tidak dapat diubah dalam, katakanlah, C, dan objek dari kelas lain di Jawa tidak dapat diubah.
David Richerby
2
Ini adalah pertanyaan tentang desain bahasa pemrograman. Sepertinya pada topik, bagi saya.
David Richerby
2
@DavidRicherby, String literal tidak dapat diubah dalam C (Dalam istilah C90: Jika program mencoba untuk memodifikasi string literal dari kedua bentuk, perilaku tidak terdefinisi. Beberapa versi awal menerimanya karena kurangnya const dalam bahasa, dan itu memang kadang-kadang apa yang diharapkan oleh programmer, tapi saya pikir itu tidak pernah didukung) Saya pikir semua orang telah belajar dari kesalahan pada FORTRAN awal yang memungkinkan untuk mengubah literal. Memiliki literal menciptakan objek baru yang bisa berubah yang nilai awalnya sama dengan literal di sisi lain jika bukan sesuatu yang tidak sehat.
Pemrogram
1
@Programmer Plenty telah menulis tentang mengapa Java dirancang seperti itu: Saya akan terkejut jika tidak ada yang otoritatif tentang keputusan desain di sekitar kelas String. Tetapi, bahkan jika perancang bahasa tidak pernah mengatakan mengapa String tidak dapat diubah, itu tidak menjadikan pertanyaan di luar topik atau bahkan buruk: itu hanya berarti bahwa, sayangnya, satu-satunya jawaban yang tepat adalah "Kami tidak tahu."
David Richerby
1
@ DavidVicherby Akan lebih baik jika pertanyaannya adalah bahasa-agnostik. Yang ini dapat dijawab dengan mengutip pernyataan dari seorang pengembang Java; kami ingin jawaban yang menjelaskan konsep.
Raphael

Jawaban:

9

Masalah ini sangat terkait dengan gagasan tentang apa artinya menjadi turunan dari kelas. Dalam istilah Object-Oriented yang ketat, sebuah kelas memiliki invarian terkait: sebuah predikat yang selalu berlaku saat keluar dari metode (publik) kelas. Gagasan semacam itu penting dalam memastikan bahwa warisan didefinisikan dengan baik, misalnya (itu adalah bagian dari Prinsip Pergantian Liskov ).

Salah satu masalah yang paling merusak dengan Java adalah sulit untuk mencegah kode klien dari melanggar kelas invarian.

Misalnya, pertimbangkan kelas 'Kode Pos' berikut:

class ZipCode {
    private String zipCode;

    public ZipCode(String value){
        if(!isValidZipCode(value))
            throw new IllegalArgumentException();
        zipCode = value;
        assert(invariant());
    }

    public String get() { return zipCode; }

    public boolean invariant() {
        return isValidZipCode( zipCode );
    }
}

Jika String tidak dapat diubah, akan mungkin bagi pengguna ZipCode untuk memanggil 'get' dan mengubah karakter pada waktu berikutnya, sehingga melanggar invarian dan menghancurkan integritas konseptual yang ditawarkan oleh enkapsulasi konsep ZipCode.

Karena integritas semacam ini sangat penting untuk memastikan bahwa sistem besar valid, jawaban untuk pertanyaan Anda ini benar-benar memohon yang lebih luas dari:

"Mengapa Java tidak mendukung analog C ++ const, atau setidaknya menawarkan versi yang tidak dapat diubah dari lebih dari kelas perpustakaan itu?"

NietzscheanAI
sumber
7

Hal-hal seperti string dan tanggal adalah nilai alami. Dalam istilah C ++, kami berharap mereka memiliki copy constructor, operator penugasan, dan operator kesetaraan, tetapi kami tidak pernah berharap untuk mengambil alamat mereka. Karenanya, kami tidak berharap mereka dialokasikan secara individu di heap. Metode virtual tidak masuk akal.

Objek domain adalah referensi alami. C ++ yang tidak memiliki copy constructor, operator penugasan, atau operator kesetaraan (mereka sama hanya jika identik). Kami dapat mengambil alamat mereka dan kami berharap mereka akan dialokasikan tumpukan. Metode umumnya virtual.

Java tidak memiliki kelas nilai, hanya yang referensi. Nilai dipalsukan dengan benda yang tidak dapat diubah. Ini berlaku untuk string, tetapi sayangnya, tidak untuk kencan. Ketidakstabilan tanggal Jawa telah menyebabkan masalah sering, dan sekarang sudah usang. Nilai yang dapat diubah tidak dapat digunakan sebagai dasar untuk hash, misalnya.

Gambar kecil
sumber
Nah, nilai yang bisa diubah dapat digunakan untuk hashing, tetapi Anda lebih baik tidak bermutasi setelahnya jika Anda mengandalkan kode hash!
gnasher729
6

Java dirancang untuk memungkinkan pelaksanaan subbagian dari kode program di lingkungan yang dibatasi keamanan. Cara persyaratan ini diterapkan adalah dengan menetapkan "SecurityManager" pada utas yang diberi akses ke parameter operasi kritis tertentu (misalnya membuka file) dan bertanya apakah operasi tersebut boleh atau tidak boleh dilanjutkan. Jika Java Strings dapat diubah, sebuah program dapat menghindari pembatasan tersebut dengan membuat dua utas, satu yang melakukan operasi file terbuka yang akan diizinkan sementara yang lain memodifikasi string yang menyimpan nama file ke salah satu yang tidak akan diizinkan. Kemudian ada kemungkinan bahwa manajer keamanan akan membaca string asli, menerima operasi, yang akan diteruskan ke kode pembukaan file yang kemudian akan membuka file kedua (tidak diizinkan).

  • string abadi
  • melakukan penyalinan defensif dari string kritis keamanan apa pun sebelum memeriksa penerimaannya.

Kemungkinan yang terakhir akan membuat semua operasi seperti itu berjalan lebih lambat dan akan lebih mungkin untuk implementasi mengandung bug, jadi menggunakan string yang tidak dapat diubah adalah keputusan yang paling masuk akal.

Secara lebih umum, objek yang tidak dapat diubah berguna karena memungkinkan berbagi tanpa perlu membuat salinan defensif (yang mungkin diperlukan bahkan dalam kode non-keamanan-kritis untuk mencegah bug ketika sumber data berubah), sehingga bahkan tanpa persyaratan ini keputusan masih akan diambil. yang masuk akal.

Jules
sumber
1
Saya senang seseorang menunjukkan ini, karena James Gosling sangat jelas tentang keputusan desain ini. Java dirancang agar Anda dapat menjalankan kode yang tidak terpercaya yang dikirimkan kepada Anda melalui jaringan (mis. Di browser web atau set top box digital). Alasan utama untuk membuat string tidak dapat diubah adalah untuk memudahkan vendor atau pengelola situs (dan pelaksana perpustakaan standar Java!) Untuk menerapkan kebijakan keamanan kustom mereka sendiri. String yang tidak dapat diubah secara efektif menutup satu vektor serangan potensial dengan desain.
Nama samaran