Buku Java yang Efektif dan sumber-sumber lain memberikan penjelasan yang cukup bagus tentang bagaimana dan kapan menggunakan metode readObject () ketika bekerja dengan kelas Java yang dapat diubah serial. Metode readResolve (), di sisi lain, tetap menjadi sedikit misteri. Pada dasarnya semua dokumen yang saya temukan hanya menyebutkan satu atau keduanya atau hanya menyebutkan satu per satu.
Pertanyaan yang tetap tidak terjawab adalah:
- Apa perbedaan antara kedua metode ini?
- Kapan metode mana yang harus diterapkan?
- Bagaimana seharusnya readResolve () digunakan, terutama dalam hal mengembalikan apa?
Saya harap Anda bisa menjelaskan masalah ini.
java
serialization
singleton
Makanan ternak
sumber
sumber
String.CaseInsensitiveComparator.readResolve()
Jawaban:
readResolve
digunakan untuk mengganti objek yang dibaca dari aliran. Satu-satunya kegunaan yang pernah saya lihat untuk ini adalah menegakkan lajang; ketika sebuah objek dibaca, gantikan dengan instance singleton. Ini memastikan bahwa tidak ada yang bisa membuat contoh lain dengan membuat serial dan deserialisasi singleton.sumber
transient
bidang.readResolve
digunakan untuk menyelesaikan objek setelah dibaca. Contoh penggunaan mungkin adalah objek yang menyimpan beberapa cache yang dapat dibuat kembali dari data yang ada dan tidak perlu diserialisasi; data yang di-cache dapat dideklarasikantransient
danreadResolve()
dapat dibangun kembali setelah deserialization. Hal-hal seperti itulah gunanya metode ini.Serializable
: dikatakan "Kelas yang perlu menunjuk pengganti ketika turunannya dibaca dari aliran harus menerapkanreadResolve
metode khusus [ ] ini ...".Butir 90, Java Efektif, sampul Ed ke-3
readResolve
danwriteReplace
untuk proxy serial - penggunaan utama mereka. Contoh tidak menulisreadObject
danwriteObject
metode karena mereka menggunakan serialisasi default untuk membaca dan menulis bidang.readResolve
dipanggil setelahreadObject
telah kembali (sebaliknyawriteReplace
dipanggil sebelumnyawriteObject
dan mungkin pada objek yang berbeda). Objek yang dikembalikan metode menggantikanthis
objek yang dikembalikan ke penggunaObjectInputStream.readObject
dan referensi kembali lebih jauh ke objek dalam aliran. KeduanyareadResolve
danwriteReplace
dapat mengembalikan objek dengan tipe yang sama atau berbeda. Mengembalikan jenis yang sama berguna dalam beberapa kasus di mana bidang harusfinal
dan kompatibilitas mundur diperlukan atau nilai harus disalin dan / atau divalidasi.Penggunaan
readResolve
tidak memberlakukan properti tunggal.sumber
readResolve dapat digunakan untuk mengubah data yang diserialisasi melalui metode readObject. Misalnya, xstream API menggunakan fitur ini untuk menginisialisasi beberapa atribut yang tidak ada dalam XML untuk diderialisasi.
http://x-stream.github.io/faq.html#Serialisasi
sumber
readResolve adalah untuk saat Anda mungkin perlu mengembalikan objek yang ada, misalnya karena Anda memeriksa duplikat input yang harus digabungkan, atau (misalnya dalam sistem terdistribusi yang akhirnya konsisten) karena ini merupakan pembaruan yang mungkin tiba sebelum Anda menyadari versi yang lebih lama.
sumber
readObject () adalah metode yang ada di class ObjectInputStream. sementara membaca objek pada saat deserialization, readObject method memeriksa secara internal apakah objek kelas yang sedang deserialisasi memiliki metode readResolve atau tidak jika ada metode readResolve maka akan memanggil metode readResolve dan mengembalikan metode readResolve yang sama. contoh.
Jadi niat menulis metode readResolve adalah praktik yang baik untuk mencapai pola desain singleton murni di mana tidak ada yang bisa mendapatkan contoh lain dengan membuat serial / deserializing.
sumber
readResolve () akan memastikan kontrak tunggal saat serialisasi.
Silakan merujuk
sumber
Ketika serialisasi digunakan untuk mengonversi objek sehingga dapat disimpan dalam file, kita dapat memicu metode, readResolve (). Metode ini bersifat pribadi dan disimpan di kelas yang sama yang objeknya diambil saat deserialisasi. Ini memastikan bahwa setelah deserialization, objek apa yang dikembalikan adalah sama dengan serial. Itu adalah,
instanceSer.hashCode() == instanceDeSer.hashCode()
Metode readResolve () bukan metode statis. Setelah
in.readObject()
dipanggil sementara deserialisation itu hanya memastikan bahwa objek yang dikembalikan adalah sama dengan yang serial seperti di bawah ini sementaraout.writeObject(instanceSer)
Dengan cara ini, ini juga membantu dalam implementasi pola desain tunggal , karena setiap kali contoh yang sama dikembalikan.
sumber
Saya tahu pertanyaan ini benar-benar tua dan memiliki jawaban yang diterima, tetapi karena muncul sangat tinggi di pencarian google, saya pikir saya akan mempertimbangkan karena tidak ada jawaban yang mencakup tiga kasus yang saya anggap penting - dalam pikiran saya penggunaan utama untuk ini metode. Tentu saja, semua berasumsi bahwa sebenarnya ada kebutuhan untuk format serialisasi khusus.
Ambil, misalnya kelas koleksi. Serialisasi serial dari daftar tertaut atau BST akan menghasilkan hilangnya ruang yang sangat besar dengan perolehan kinerja yang sangat sedikit dibandingkan dengan hanya membuat serial elemen-elemen secara berurutan. Ini bahkan lebih benar jika koleksi adalah proyeksi atau tampilan - menyimpan referensi ke struktur yang lebih besar daripada yang diekspos oleh API publiknya.
Jika objek berseri memiliki bidang yang tidak dapat diubah yang membutuhkan serialisasi khusus, solusi asli
writeObject/readObject
tidak mencukupi, karena objek deserialisasi dibuat sebelum membaca bagian aliran yang dituliswriteObject
. Ambil penerapan minimal dari daftar tertaut ini:Struktur ini dapat diserialisasi dengan menulis
head
bidang setiap tautan secara rekursif , diikuti oleh sebuahnull
nilai. Namun deserialisasi format seperti itu menjadi tidak mungkin:readObject
tidak dapat mengubah nilai-nilai bidang anggota (sekarang diperbaiki kenull
). Berikut datangwriteReplace
/readResolve
pair:Saya minta maaf jika contoh di atas tidak mengkompilasi (atau bekerja), tetapi mudah-mudahan cukup untuk menggambarkan poin saya. Jika menurut Anda ini adalah contoh yang sangat jauh, harap diingat bahwa banyak bahasa fungsional dijalankan pada JVM dan pendekatan ini menjadi sangat penting dalam kasus mereka.
Kita mungkin ingin melakukan deserialisasi objek dari kelas yang berbeda dari yang kita tulis ke
ObjectOutputStream
. Ini akan menjadi kasus dengan pandangan sepertijava.util.List
implementasi daftar yang memperlihatkan sepotong lebih lamaArrayList
. Jelas, membuat serial seluruh daftar dukungan adalah ide yang buruk dan kita hanya harus menulis elemen dari slice yang dilihat. Tetapi mengapa berhenti pada itu dan memiliki tingkat tipuan yang tidak berguna setelah deserialisasi? Kami hanya bisa membaca elemen dari aliran ke dalamArrayList
dan mengembalikannya secara langsung alih-alih membungkusnya di kelas tampilan kami.Atau, memiliki kelas delegasi serupa yang didedikasikan untuk serialisasi dapat menjadi pilihan desain. Contoh yang baik akan menggunakan kembali kode serialisasi kami. Sebagai contoh, jika kita memiliki kelas builder (mirip dengan StringBuilder untuk String), kita dapat menulis delegasi serialisasi yang membuat serial setiap koleksi dengan menulis builder kosong ke stream, diikuti dengan ukuran koleksi dan elemen yang dikembalikan oleh iterator colection. Deserialisasi akan melibatkan pembacaan pembangun, menambahkan semua elemen yang selanjutnya dibaca, dan mengembalikan hasil final
build()
dari delegasireadResolve
. Dalam hal ini kita perlu mengimplementasikan serialisasi hanya di kelas akar hirarki koleksi, dan tidak ada kode tambahan yang diperlukan dari implementasi saat ini atau di masa depan, asalkan mereka menerapkan abstrakiterator()
danbuilder()
metode (yang terakhir untuk membuat ulang koleksi dari jenis yang sama - yang akan menjadi fitur yang sangat berguna dalam dirinya sendiri). Contoh lain adalah memiliki hierarki kelas yang kode kita tidak sepenuhnya kendalikan - kelas dasar kita dari pustaka pihak ketiga dapat memiliki sejumlah bidang pribadi yang tidak kita ketahui dan yang dapat berubah dari satu versi ke versi lain, melanggar objek serial kami. Dalam hal ini akan lebih aman untuk menulis data dan membangun kembali objek secara manual pada deserialisasi.sumber
Metode readResolve
Untuk kelas Serializable dan Externalizable, metode readResolve memungkinkan kelas untuk mengganti / menyelesaikan objek yang dibaca dari aliran sebelum dikembalikan ke pemanggil. Dengan mengimplementasikan metode readResolve, sebuah kelas dapat secara langsung mengontrol tipe dan instance dari instance miliknya sendiri yang dideeralisasi. Metode ini didefinisikan sebagai berikut:
ANY-ACCESS-MODIFIER Object readResolve () melempar ObjectStreamException;
The readResolve metode ini disebut ketika ObjectInputStream telah membaca sebuah objek dari sungai dan sedang mempersiapkan untuk kembali ke pemanggil. ObjectInputStream memeriksa apakah kelas objek mendefinisikan metode readResolve. Jika metode ini didefinisikan, metode readResolve dipanggil untuk memungkinkan objek dalam aliran untuk menunjuk objek yang akan dikembalikan. Objek yang dikembalikan harus dari tipe yang kompatibel dengan semua penggunaan. Jika tidak kompatibel, ClassCastException akan dilemparkan ketika tipe ketidakcocokan ditemukan.
Misalnya, kelas Simbol dapat dibuat yang hanya ada satu contoh dari setiap simbol yang mengikat ada dalam mesin virtual. The readResolve Metode akan dilaksanakan untuk menentukan apakah simbol yang sudah ditetapkan dan menggantikan yang sudah ada sebelumnya setara objek Simbol untuk mempertahankan kendala identitas. Dengan cara ini keunikan objek Simbol dapat dipertahankan di seluruh serialisasi.
sumber
Seperti yang sudah dijawab,
readResolve
adalah metode pribadi yang digunakan dalam ObjectInputStream saat deserializing objek. Ini disebut tepat sebelum instance aktual dikembalikan. Dalam kasus Singleton, di sini kita dapat memaksa mengembalikan referensi instance singleton yang sudah ada alih-alih referensi instance deserialized. Sama seperti yang kita milikiwriteReplace
untuk ObjectOutputStream.Contoh untuk
readResolve
:}
Keluaran:
sumber