Dari ketika saya mengetahui bahwa kelas java.lang.String
dinyatakan sebagai final di Jawa, saya bertanya-tanya mengapa itu. Saya tidak menemukan jawaban saat itu, tetapi posting ini: Bagaimana cara membuat replika kelas String di Jawa? mengingatkan saya pada pertanyaan saya.
Tentu, String menyediakan semua fungsionalitas yang pernah saya butuhkan, dan saya tidak pernah memikirkan operasi apa pun yang membutuhkan ekstensi kelas String, tetapi Anda tetap tidak akan pernah tahu apa yang mungkin dibutuhkan seseorang!
Jadi, adakah yang tahu apa maksud para desainer itu ketika mereka memutuskan untuk menjadikannya final?
Jawaban:
Sangat berguna untuk menerapkan string sebagai objek yang tidak berubah . Anda harus membaca tentang kekekalan untuk memahami lebih banyak tentang itu.
Satu keuntungan dari objek yang tidak berubah adalah itu
(dari sini ).
Jika String tidak final, Anda bisa membuat subclass dan memiliki dua string yang mirip ketika "dilihat sebagai String", tetapi itu sebenarnya berbeda.
sumber
Ini adalah artikel yang bagus yang menguraikan dua alasan yang telah disebutkan pada jawaban di atas:
Dan ini mungkin komentar paling detail dalam artikel itu. Ini ada hubungannya dengan kumpulan string di Jawa dan masalah keamanan. Ini tentang bagaimana memutuskan apa yang masuk ke kolam string. Dengan asumsi kedua string sama jika urutan karakter mereka sama, maka kita memiliki kondisi balapan tentang siapa yang sampai di sana terlebih dahulu dan bersamaan dengan itu masalah keamanan. Jika tidak, maka kumpulan string akan berisi string yang berlebihan sehingga kehilangan keuntungan dari memilikinya di tempat pertama. Bacakan saja sendiri, ya?
Extending String akan memainkan malapetaka dengan equals dan intern. JavaDoc mengatakan equals:
Dengan asumsi
java.lang.String
itu belum final, aSafeString
bisa sama denganString
, dan sebaliknya; karena mereka mewakili urutan karakter yang sama.Apa yang akan terjadi jika Anda melamar
intern
keSafeString
- apakahSafeString
masuk ke kumpulan string JVM? TheClassLoader
dan semua objek yangSafeString
referensi diadakan untuk kemudian akan mendapatkan terkunci di tempat untuk seumur hidup dari JVM. Anda akan mendapatkan kondisi balapan tentang siapa yang bisa menjadi orang pertama yang magang serangkaian karakter - mungkin AndaSafeString
akan menang, mungkin aString
, atau mungkinSafeString
dimuat oleh classloader yang berbeda (dengan demikian kelas yang berbeda).Jika Anda memenangkan perlombaan ke kolam renang, ini akan menjadi singleton sejati dan orang-orang dapat mengakses seluruh lingkungan Anda (kotak pasir) melalui refleksi dan
secretKey.intern().getClass().getClassLoader()
.Atau JVM dapat memblokir lubang ini dengan memastikan bahwa hanya objek String beton (dan tidak ada subkelas) yang ditambahkan ke kumpulan.
Jika persamaan diterapkan sedemikian rupa
SafeString
! =String
MakaSafeString.intern
! =String.intern
, DanSafeString
harus ditambahkan ke kumpulan. Kolam kemudian akan menjadi kolam<Class, String>
bukan<String>
dan semua yang Anda butuhkan untuk memasuki kolam akan menjadi classloader segar.sumber
Alasan yang paling penting bahwa String tidak dapat diubah atau final adalah bahwa String digunakan oleh mekanisme pemuatan kelas, dan dengan demikian memiliki aspek keamanan yang mendasar dan mendasar.
Seandainya String tidak bisa diubah atau belum final, permintaan untuk memuat "java.io.Writer" dapat diubah untuk memuat "mil.vogoon.DiskErasingWriter"
referensi: Mengapa String tidak dapat diubah di Jawa
sumber
String
adalah kelas yang sangat inti di Jawa, banyak hal bergantung padanya bekerja dengan cara tertentu, misalnya menjadi tidak berubah.Membuat kelas
final
mencegah subclass yang bisa mematahkan asumsi ini.Perhatikan bahwa, bahkan sekarang, jika Anda menggunakan refleksi, Anda dapat memecah Strings (mengubah nilai atau kode hash). Refleksi dapat dihentikan dengan manajer keamanan. Jika
String
tidakfinal
, semua orang bisa melakukannya.Kelas-kelas lain yang tidak dideklarasikan
final
memungkinkan Anda untuk mendefinisikan subclass yang agak rusak (Anda bisa memilikiList
yang menambah posisi yang salah, misalnya) tetapi setidaknya JVM tidak bergantung pada mereka untuk operasi intinya.sumber
final
di kelas tidak menjamin kekekalan. Ini hanya menjamin bahwa invarian kelas (salah satunya bisa berubah) tidak dapat diubah oleh sub-kelas.Seperti yang dikatakan Bruno, ini tentang kekekalan. Ini bukan hanya tentang Strings tetapi juga tentang pembungkus misalnya Double, Integer, Karakter, dll. Ada banyak alasan untuk ini:
Pada dasarnya itu agar Anda, sebagai programmer, dapat memastikan bahwa string Anda tidak akan pernah berubah. Itu juga, jika Anda tahu cara kerjanya, dapat meningkatkan manajemen memori. Cobalah untuk membuat dua string yang identik satu demi satu, misalnya "halo". Anda akan melihat, jika Anda men-debug, bahwa mereka memiliki ID yang identik, itu berarti bahwa mereka persis objek SAMA. Ini disebabkan oleh fakta bahwa Java memungkinkan Anda melakukannya. Ini tidak akan mungkin jika string dapat dipecahkan. Mereka dapat memiliki aku yang sama, dll., Karena mereka tidak akan pernah berubah. Jadi jika Anda pernah memutuskan untuk membuat 1.000.000 string "halo" yang benar-benar Anda lakukan adalah membuat 1.000.000 petunjuk untuk "halo". Serta menyatukan fungsi apa pun pada string, atau pembungkus apa pun untuk alasan itu, akan menghasilkan pembuatan objek lain (sekali lagi lihat ID objek - itu akan berubah).
Final di Jawa tidak selalu berarti bahwa objek tidak dapat berubah (berbeda dengan misalnya C ++). Ini berarti bahwa alamat yang ditunjuknya tidak dapat diubah, tetapi Anda masih dapat mengubah properti dan / atau atributnya. Jadi memahami perbedaan antara kekekalan dan final dalam beberapa kasus mungkin sangat penting.
HTH
Referensi:
sumber
Mungkin untuk menyederhanakan implementasi. Jika Anda mendesain kelas yang akan diwariskan oleh pengguna kelas, maka Anda memiliki satu set kasus penggunaan yang sama sekali baru untuk dipertimbangkan ke dalam desain Anda. Apa yang terjadi jika mereka melakukan ini atau itu dengan bidang proptected X? Menjadikannya final, mereka dapat fokus untuk membuat antarmuka publik berfungsi dengan benar dan memastikannya solid.
sumber
Dengan banyak poin bagus yang telah disebutkan saya ingin menambahkan satu lagi -salah satu alasan Mengapa String tidak dapat diubah di Jawa adalah untuk memungkinkan String untuk me-cache hashcode-nya , menjadi String yang tidak dapat diubah di Jawa cache hashcode-nya, dan tidak menghitung setiap kali kita memanggil metode kode hash String , yang membuatnya sangat cepat sebagai kunci hashmap untuk digunakan dalam hashmap di Jawa.
Singkatnya karena String tidak dapat diubah, tidak ada yang dapat mengubah isinya yang pernah dibuat yang menjamin kode hash String sama pada beberapa pemanggilan.
Jika Anda melihat
String
kelas telah dinyatakan sebagaidan
hashcode()
fungsinya adalah sebagai berikut -Jika sudah komputer cukup kembalikan nilainya.
sumber
Untuk memastikan kami tidak mendapatkan implementasi yang lebih baik. Tentu saja itu seharusnya sebuah antarmuka.
[sunting] Ah, mendapatkan lebih banyak suara yang tidak mengerti. Jawabannya sangat serius. Saya harus memprogram jalan saya di sekitar implementasi String bodoh beberapa kali, yang mengarah ke kinerja yang parah & hilangnya produktivitas
sumber
Terlepas dari alasan yang jelas yang disarankan dalam jawaban lain, satu pemikiran untuk membuat kelas String akhir juga dapat dikaitkan dengan overhead kinerja metode virtual. Ingat String adalah kelas berat, membuat ini final, berarti tidak ada sub-implementasi pasti, berarti tidak ada tipuan yang memanggil overhead. Tentu saja sekarang kami memiliki hal-hal seperti pemanggilan virtual dan lainnya, yang selalu melakukan optimasi semacam ini untuk Anda.
sumber
Selain alasan yang disebutkan dalam jawaban lain (keamanan, kekekalan, kinerja) harus dicatat bahwa
String
memiliki dukungan bahasa khusus. Anda dapat menulisString
literal dan ada dukungan untuk+
operator. Mengizinkan pemrogram untuk subkelasString
, akan mendorong peretasan seperti:sumber
Yah, saya punya beberapa pemikiran yang berbeda saya tidak yakin apakah saya benar atau tidak tetapi dalam Java String adalah satu-satunya objek yang dapat diperlakukan sebagai tipe data primitif juga maksud saya kita dapat membuat objek String sebagai String name = "java " . Sekarang seperti tipe data primitif lainnya yang disalin oleh nilai, bukan menyalin dengan referensi, String diharapkan memiliki perilaku yang sama, jadi itu sebabnya String bersifat final. Itulah yang saya pikirkan. Harap abaikan jika ini sama sekali tidak masuk akal.
sumber
Finalitas string juga membela mereka sebagai standar. Di C ++ Anda bisa membuat subclass dari string, sehingga setiap toko pemrograman bisa memiliki versi stringnya sendiri. Ini akan menyebabkan kurangnya standar yang kuat.
sumber
Katakanlah Anda memiliki
Employee
kelas yang memiliki metodegreet
. Ketikagreet
metode ini disebut hanya mencetakHello everyone!
. Jadi itu adalah perilaku yang diharapkan darigreet
metodeSekarang, biarkan metode
GrumpyEmployee
subclassEmployee
dan overridegreet
seperti yang ditunjukkan di bawah ini.Sekarang dalam kode di bawah ini lihat
sayHello
metode. DibutuhkanEmployee
instance sebagai parameter dan memanggil metode sapaan berharap itu akan mengatakanHello everyone!
Tapi apa yang kita dapatkan adalahGet lost!
. Perubahan perilaku ini karenaEmployee grumpyEmployee = new GrumpyEmployee();
Situasi ini dapat dihindari jika
Employee
kelas dibuatfinal
. Sekarang terserah pada imajinasi Anda jumlah kekacauan yang bisa disebabkan oleh programmer yang nakal jikaString
Kelas tidak dinyatakan sebagaifinal
.sumber
Apakah JVM tahu apa yang tidak bisa diubah? Jawabannya adalah Tidak, kolam konstan berisi semua bidang tidak berubah tetapi semua bidang tidak berubah hanya disimpan di kolam konstan saja. Hanya kami menerapkannya dengan cara yang mencapai ketidakmampuan dan fitur-fiturnya. CustomString dapat diimplementasikan tanpa membuatnya final menggunakan MarkerInterface yang akan memberikan perilaku khusus java untuk penyatuannya, fitur ini masih ditunggu!
sumber
Sebagian besar jawaban terkait dengan ketidakmampuan - mengapa objek tipe String tidak dapat diperbarui di tempat. Ada banyak diskusi yang baik di sini, dan masyarakat Jawa sebaiknya mengadopsi kekekalan sebagai kepala sekolah. (Tidak menahan napas.)
Namun pertanyaan OP adalah tentang mengapa itu final - mengapa tidak bisa diperpanjang. Beberapa di sini memang mengambil ini, tetapi saya akan setuju dengan OP bahwa ada celah nyata di sini. Bahasa lain memungkinkan pengembang membuat jenis nominal baru untuk suatu jenis. Sebagai contoh di Haskell saya dapat membuat tipe baru berikut ini yang identik pada saat run-time sebagai teks, tetapi memberikan keamanan-mengikat pada waktu kompilasi.
Jadi saya akan mengajukan saran berikut sebagai tambahan untuk bahasa Java:
(Atau mungkin kita bisa mulai melepaskan diri dari Jawa)
sumber
Jika Anda membuat string sekali Ini akan mempertimbangkan itu, itu adalah objek jika Anda ingin memodifikasi itu, itu tidak mungkin, itu akan membuat objek baru.
sumber