Pertanyaan Apa itu serialVersionUID dan mengapa saya harus menggunakannya?


Eclipse mengeluarkan peringatan ketika a serialVersionUID hilang.

Kelas yang dapat dikategorikan Foo tidak menyatakan final statis   bidang serialVersionUID bertipe panjang

apa yang serialVersionUID dan mengapa itu penting? Tolong tunjukkan contoh di mana hilang serialVersionUID akan menimbulkan masalah.


2482
2017-11-12 23:24


asal


Jawaban:


Dokumen untuk java.io.Serializable mungkin merupakan penjelasan yang sebaik yang akan Anda dapatkan:

Associate runtime serialization   dengan masing-masing kelas serialable   angka, disebut serialVersionUID,   yang digunakan selama deserialization   untuk memverifikasi bahwa pengirim dan penerima   dari objek serial telah dimuat   kelas untuk objek itu   kompatibel sehubungan dengan   serialisasi. Jika penerima memiliki   memuat kelas untuk objek yang ada   serialVersionUID yang berbeda dari itu   dari kelas pengirim yang sesuai,   maka deserialisasi akan menghasilkan suatu    InvalidClassException. Sebuah serializable   kelas dapat mendeklarasikan miliknya   serialVersionUID secara eksplisit oleh   menyatakan bidang bernama   "serialVersionUID" itu pasti   statis, final, dan tipe long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

Jika sebuah   kelas serializable tidak secara eksplisit   mendeklarasikan serialVersionUID, lalu   runtime serialisasi akan menghitung a   nilai serialVersionUID default untuk   kelas yang didasarkan pada berbagai aspek   kelas, seperti yang dijelaskan dalam   Java (TM) Object Serialization   Spesifikasi. Namun demikian dengan kuat   direkomendasikan bahwa semua serializable   kelas-kelas secara eksplisit menyatakan   nilai serialVersionUID, karena   perhitungan serialVersionUID default   sangat sensitif terhadap detail kelas   yang dapat bervariasi tergantung pada kompilator   implementasi, dan dengan demikian dapat menghasilkan   secara tak terduga InvalidClassExceptions   selama deserialization. Karena itu, untuk   menjamin yang konsisten   nilai serialVersionUID   java compiler yang berbeda   implementasi, kelas yang dapat diprogramkan   harus menyatakan eksplisit   nilai serialVersionUID. Itu juga   sangat menyarankan bahwa eksplisit   deklarasi serialVersionUID menggunakan   pengubah pribadi jika memungkinkan, sejak   deklarasi tersebut hanya berlaku untuk   segera menyatakan   class - field serialVersionUID tidak   berguna sebagai anggota yang diwariskan.


1910
2017-11-12 23:30



Jika Anda melakukan serialisasi hanya karena Anda harus membuat serial untuk kepentingan implementasi (siapa yang peduli jika Anda membuat serial untuk HTTPSession, misalnya ... jika disimpan atau tidak, Anda mungkin tidak peduli dengan de-serialisasi objek formulir) , maka Anda bisa mengabaikan ini.

Jika Anda benar-benar menggunakan serialisasi, itu hanya masalah jika Anda berencana menyimpan dan mengambil objek menggunakan serialisasi secara langsung. SerialVersionUID mewakili versi kelas Anda, dan Anda harus menaikkannya jika versi saat ini dari kelas Anda tidak kompatibel dengan versi sebelumnya.

Seringkali, Anda mungkin tidak akan menggunakan serialisasi secara langsung. Jika ini kasusnya, buat default uid serialized dengan mengklik opsi perbaikan cepat dan jangan khawatir tentang itu.


415
2017-11-13 04:24



Saya tidak bisa melewatkan kesempatan ini untuk menghubungkan buku Josh Bloch Java yang efektif (Edisi 2). Bab 11 adalah sumber yang sangat penting dalam serialisasi Java.

Per Josh, UID yang dihasilkan secara otomatis dihasilkan berdasarkan nama kelas, antarmuka yang diimplementasikan, dan semua anggota publik dan dilindungi. Mengubah semua ini dengan cara apa pun akan mengubah serialVersionUID. Jadi Anda tidak perlu mengacaukannya hanya jika Anda yakin bahwa tidak ada lebih dari satu versi kelas yang akan diserialisasi (baik di seluruh proses atau diambil dari penyimpanan di lain waktu).

Jika Anda mengabaikannya untuk saat ini, dan menemukan kemudian bahwa Anda perlu mengubah kelas dengan cara tertentu tetapi mempertahankan kompatibilitas dengan versi lama dari kelas, Anda dapat menggunakan alat JDK serialver untuk menghasilkan serialVersionUID pada tua kelas, dan secara eksplisit mengatur itu di kelas baru. (Tergantung pada perubahan Anda, Anda mungkin perlu juga menerapkan serialisasi kustom dengan menambahkan writeObject dan readObject metode - lihat Serializable javadoc atau bab 11 tersebut.)


264
2017-11-12 23:37



Anda dapat memberi tahu Eclipse untuk mengabaikan peringatan serialVersionUID ini:

Jendela> Preferensi> Java> Compiler> Kesalahan / Peringatan> Masalah Pemrograman Potensial

Jika Anda tidak tahu, ada banyak peringatan lain yang dapat Anda aktifkan di bagian ini (atau bahkan dilaporkan sebagai kesalahan), banyak yang sangat berguna:

  • Masalah Pemrograman Potensi: Kemungkinan penugasan boolean yang tidak disengaja
  • Masalah Pemrograman Potensi: Akses pointer Null
  • Kode yang tidak perlu: Variabel lokal tidak pernah dibaca
  • Kode yang tidak perlu: Redundant null check
  • Kode yang tidak perlu: Pemeran tidak perlu atau 'instanceof'

dan masih banyak lagi.


124
2017-11-13 01:17



serialVersionUID memfasilitasi versi dari data serial. Nilainya disimpan dengan data saat serialisasi. Ketika de-serialisasi, versi yang sama dicentang untuk melihat bagaimana data serial sesuai dengan kode saat ini.

Jika Anda ingin versi data Anda, Anda biasanya mulai dengan serialVersionUID 0, dan menabraknya dengan setiap perubahan struktural ke kelas Anda yang mengubah data serial (menambahkan atau menghapus bidang non-sementara).

Mekanisme de-serialisasi bawaan (in.defaultReadObject()) akan menolak melakukan de-serialisasi dari versi lama data. Tetapi jika Anda ingin Anda dapat menentukan sendiri readObject ()-fungsi yang dapat membaca kembali data lama. Kode kustom ini kemudian dapat memeriksa serialVersionUID untuk mengetahui versi mana data dan memutuskan bagaimana cara membatalkannya. Teknik versi ini berguna jika Anda menyimpan data serial yang bertahan dari beberapa versi kode Anda.

Tetapi menyimpan data serial untuk rentang waktu yang lama tidak terlalu umum. Jauh lebih umum untuk menggunakan mekanisme serialisasi untuk menulis sementara data ke misalnya cache atau mengirimkannya melalui jaringan ke program lain dengan versi yang sama dari bagian yang relevan dari basis kode.

Dalam hal ini Anda tidak tertarik untuk mempertahankan kompatibilitas ke belakang. Anda hanya peduli dengan memastikan bahwa basis kode yang berkomunikasi memang memiliki versi yang sama dari kelas yang relevan. Untuk memfasilitasi pemeriksaan semacam itu, Anda harus mempertahankan serialVersionUIDsama seperti sebelumnya dan jangan lupa untuk memperbaruinya saat membuat perubahan ke kelas Anda.

Jika Anda lupa untuk memperbarui bidang, Anda mungkin berakhir dengan dua versi berbeda dari suatu kelas dengan struktur yang berbeda tetapi dengan yang sama serialVersionUID. Jika ini terjadi, mekanisme default (in.defaultReadObject()) tidak akan mendeteksi perbedaan apa pun, dan mencoba membatalkan-seri data yang tidak kompatibel. Sekarang Anda mungkin berakhir dengan kesalahan runtime cryptic atau silent failure (field null). Jenis kesalahan ini mungkin sulit ditemukan.

Jadi untuk membantu penggunaan ini, platform Java menawarkan Anda pilihan untuk tidak mengatur serialVersionUID secara manual. Sebagai gantinya, hash dari struktur kelas akan dihasilkan pada waktu kompilasi dan digunakan sebagai id. Mekanisme ini akan memastikan bahwa Anda tidak pernah memiliki struktur kelas yang berbeda dengan id yang sama, sehingga Anda tidak akan mendapatkan kegagalan serialisasi runtime yang sulit diketemukan di atas.

Tapi ada bagian belakang untuk strategi id yang dihasilkan otomatis. Yaitu bahwa id yang dihasilkan untuk kelas yang sama mungkin berbeda antara compiler (seperti yang disebutkan oleh Jon Skeet di atas). Jadi, jika Anda mengkomunikasikan data serial antara kode yang dikompilasi dengan kompiler yang berbeda, disarankan untuk tetap mempertahankan id secara manual.

Dan jika Anda kompatibel dengan data Anda seperti dalam kasus penggunaan pertama yang disebutkan, Anda mungkin juga ingin mempertahankan id Anda sendiri. Ini untuk mendapatkan ID yang dapat dibaca dan memiliki kontrol lebih besar terhadap kapan dan bagaimana mereka berubah.


96
2017-10-03 06:05



Apa itu serialVersionUID dan mengapa saya harus menggunakannya?

SerialVersionUID adalah pengenal unik untuk setiap kelas, JVM menggunakannya untuk membandingkan versi kelas yang memastikan bahwa kelas yang sama digunakan selama serialisasi dimuat selama Deserialization.

Menentukan satu memberikan lebih banyak kontrol, meskipun JVM menghasilkan satu jika Anda tidak menentukan. Nilai yang dihasilkan dapat berbeda antara kompiler yang berbeda. Lebih jauh lagi, kadang-kadang Anda hanya ingin untuk beberapa alasan untuk melarang deserialization objek serial lama [backward incompatibility], dan dalam hal ini Anda hanya perlu mengubah serialVersionUID.

Itu javadocs untuk Serializable mengatakan:

perhitungan serialVersionUID default sangat sensitif terhadap kelas   rincian yang dapat bervariasi tergantung pada implementasi compiler, dan dapat   sehingga menghasilkan tak terduga InvalidClassExceptions selama   deserialisasi.

Oleh karena itu, Anda harus menyatakan serialVersionUID karena itu memberi kita kontrol lebih besar.

Artikel ini memiliki beberapa poin bagus tentang topik ini.


62
2017-10-17 04:28



Pertanyaan orisinal telah menanyakan 'mengapa itu penting' dan 'contoh' di mana ini Serial Version ID akan berguna. Yah saya telah menemukan satu.

Katakanlah Anda membuat file Car kelas, instantiate, dan tuliskan ke aliran objek. Objek mobil diratakan duduk di sistem file untuk beberapa waktu. Sementara itu, jika Car kelas dimodifikasi dengan menambahkan bidang baru. Kemudian, ketika Anda mencoba membaca (yaitu deserialize) yang rata Car objek, Anda mendapatkan java.io.InvalidClassException - Karena semua kelas yang bisa diseragamkan secara otomatis diberi pengenal unik. Pengecualian ini dilempar ketika identifier kelas tidak sama dengan identifier dari objek yang diratakan. Jika Anda benar-benar memikirkannya, pengecualian dilempar karena penambahan bidang baru. Anda dapat menghindari pengecualian ini dilemparkan dengan mengontrol versi sendiri dengan menyatakan serialVersionUID eksplisit. Ada juga manfaat kinerja kecil dalam mendeklarasikan Anda secara eksplisit serialVersionUID(karena tidak harus dihitung). Jadi, praktik terbaik adalah menambahkan serialVersionUID Anda sendiri ke kelas Serializable Anda segera setelah Anda membuatnya seperti yang ditunjukkan di bawah ini:

public class Car {
static final long serialVersionUID = 1L; //assign a long value
}

41
2018-04-07 10:43



Jika Anda mendapatkan peringatan ini di kelas yang tidak pernah Anda pikirkan tentang serialisasi, dan Anda tidak menyatakan diri implements Serializable, sering karena Anda mewarisi dari superclass, yang mengimplementasikan Serializable. Seringkali kemudian akan lebih baik untuk mendelegasikan ke objek seperti itu daripada menggunakan warisan.

Jadi, bukannya

public class MyExample extends ArrayList<String> {

    public MyExample() {
        super();
    }
    ...
}

melakukan

public class MyExample {
    private List<String> myList;

    public MyExample() {
         this.myList = new ArrayList<String>();
    }
    ...
}

dan dalam panggilan metode yang relevan myList.foo() dari pada this.foo() (atau super.foo()). (Ini tidak cocok dalam semua kasus, tetapi masih cukup sering.)

Saya sering melihat orang-orang memperluas JFrame atau semacamnya, ketika mereka benar-benar hanya perlu mendelegasikan ini. (Ini juga membantu untuk menyelesaikan secara otomatis dalam IDE, karena JFrame memiliki ratusan metode, yang tidak Anda perlukan ketika Anda ingin memanggil perangkat khusus di kelas Anda.)

Satu kasus di mana peringatan (atau serialVersionUID) tidak dapat dihindari adalah ketika Anda memperpanjang dari AbstractAction, biasanya di kelas anonim, hanya menambahkan metode actionPerformed. Saya pikir seharusnya tidak ada peringatan dalam kasus ini (karena Anda biasanya tidak dapat diandalkan untuk membuat serial dan deserialize kelas anonim seperti itu di versi yang berbeda dari kelas Anda), tetapi saya tidak yakin bagaimana compiler dapat mengenali ini.


33
2018-02-03 00:32



Jika Anda tidak akan pernah perlu membuat serial objek Anda ke array byte dan mengirim / menyimpannya, maka Anda tidak perlu khawatir tentang itu. Jika Anda melakukannya, maka Anda harus mempertimbangkan serialVersionUID Anda karena deserializer objek akan mencocokkannya dengan versi objek yang dimiliki classloadernya. Baca lebih lanjut tentang itu di Spesifikasi Bahasa Jawa.


30
2017-11-12 23:30



Untuk memahami signifikansi dari field serialVersionUID, seseorang harus memahami bagaimana Serialization / Deserialization bekerja.

Ketika objek kelas Serializable adalah serial Java Runtime associates versi serial no. (Disebut sebagai serialVersionUID) dengan objek serial ini. Pada saat Anda deserialize objek serial ini Java Runtime cocok dengan serialVersionUID dari objek serialisasi dengan serialVersionUID dari kelas. Jika keduanya sama maka hanya hasil dengan proses deserialization lebih lanjut yang lain melempar InvalidClassException.

Jadi kami menyimpulkan bahwa untuk membuat serialisasi / Deserialization proses sukses serialVersionUID dari objek serial harus setara dengan serialVersionUID dari kelas. Dalam hal jika programmer menentukan nilai serialVersionUID secara eksplisit dalam program maka nilai yang sama akan dikaitkan dengan objek serial dan kelas, terlepas dari serialisasi dan platform deserialzation (untuk ex. Serialisasi mungkin dilakukan pada platform seperti windows dengan menggunakan matahari atau MS JVM dan Deserialization mungkin pada platform Linux yang berbeda menggunakan Zing JVM).

Tetapi dalam kasus jika serialVersionUID tidak ditentukan oleh programmer kemudian saat melakukan Serialisasi \ DeSerialization objek apapun, Java runtime menggunakan algoritma sendiri untuk menghitungnya. Algoritma perhitungan serialVersionUID ini bervariasi dari satu JRE ke yang lain. Ada juga kemungkinan bahwa lingkungan di mana objek diserialkan menggunakan satu JRE (ex: SUN JVM) dan lingkungan di mana deserialisasi terjadi menggunakan Linux Jvm (zing). Dalam kasus-kasus seperti itu, serialVersionUID yang dikaitkan dengan objek serial akan berbeda dari kelas serialVersionUID yang dihitung di lingkungan deserialisasi. Pada gilirannya deserialisasi tidak akan berhasil. Jadi untuk menghindari situasi seperti / masalah programmer harus selalu menentukan serialVersionUID dari kelas Serializable.


19
2018-06-02 06:20



Jangan repot-repot, perhitungan standar sangat bagus dan cukup untuk 99,9999% dari kasus. Dan jika Anda mengalami masalah, Anda dapat - seperti yang telah dinyatakan - memperkenalkan UID sebagai kebutuhan (yang sangat tidak mungkin)


18
2018-04-29 15:59