24 Soru: SerialVersionUID nedir ve neden kullanmalıyım?
Eclipse, bir
serialVersionUID eksik olduğunda uyarılar verir.
Serileştirilebilir sınıf Foo statik bir final bildirmedi serialVersionUID uzun alan alanı
serialVersionUID nedir ve neden önemlidir? Lütfen,
serialVersionUID'un kaybolmasının soruna neden olacağı bir örnek gösterin.
java.io.Serializable muhtemelen alabileceğiniz kadar iyi bir açıklama niteliğindedir:
Serileştirme çalışma zamanı, serileştirme sırasında serileştirilmiş bir nesnenin göndericisinin ve alıcısının serileştirmeyle uyumlu olan sınıfları yüklemiş olduğunu doğrulamak için serileştirme sırasında kullanılan
serialVersionUIDadlı bir sürüm numarasıyla ilişkilendirilir. Alıcı, karşılık gelen gönderenin sınıfından farklı bir
serialVersionUIDdeğerine sahip nesne için bir sınıf yüklediyse, seri kaldırma
InvalidClassException. Serileştirilebilir bir sınıf,
serialVersionUIDadında statik, son ve
serialVersionUIDtüründe bir alan bildirerek kendi
long'unu açıkça ilan edebilir:
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
Serileştirilebilir bir sınıf açıkça bir
serialVersionUIDbildirmiyorsa, serileştirme çalışma zamanı, Java (TM) Nesne Serileştirme Belirtimi'nde açıklandığı gibi, sınıfın çeşitli yönlerine göre bu sınıf için varsayılan bir
serialVersionUIDdeğeri hesaplar. Bununla birlikte, varsayılan
serialVersionUIDhesaplaması, derleyici uygulamalarına bağlı olarak değişebilecek olan sınıf ayrıntılarına karşı son derece hassas olduğundan ve bu nedenle seri hale getirme sırasında beklenmedik
serialVersionUID'a neden olabileceğinden, tüm seri hale getirilebilir sınıfların açıkça
InvalidClassExceptionsdeğerlerini açıklaması şiddetle tavsiye edilir . . Bu nedenle, farklı java derleyici uygulamalarında tutarlı bir
serialVersionUIDdeğerini garanti etmek için serileştirilebilir bir sınıfın açık bir
serialVersionUIDdeğeri bildirmesi gerekir. Ayrıca açık
serialVersionUIDbeyannamelerin mümkün olan durumlarda özel değiştiriciyi kullanması şiddetle tavsiye edilir, çünkü bu beyanlar sadece ilan eden
serialVersionUIDsınıfı ilan edilen alanlar için geçerli değildir.
Sadece uygulamanın iyiliği için serileştirmeniz gerektiğinden serileştiriyorsanız (örneğin,
HTTPSession için serileştirme umurunda olan) ), o zaman bunu görmezden gelebilirsiniz.
Gerçekten serileştirme kullanıyorsanız, yalnızca doğrudan serileştirmeyi kullanarak nesneleri kaydetmeyi ve almayı planlıyorsanız önemlidir.
de-serializing, sınıf sürümünüzü temsil eder ve sınıfınızın geçerli sürümü önceki sürümüyle geriye dönük değilse, artırmalısınız.
Çoğu zaman, seri hale getirmeyi doğrudan kullanmayacaksınız. Bu durumda, hızlı düzeltme seçeneğini tıklatarak varsayılan bir
serialVersionUID oluşturun ve bu konuda endişelenmeyin.
Josh Bloch'un kitabını eklemek için bu fırsatı yakalayamıyorum. Etkili Java (2. Baskı). Bölüm 11, Java serileştirme için vazgeçilmez bir kaynaktır.
Josh başına, otomatik olarak oluşturulan UID, bir sınıf adına, uygulanan arayüzlere ve tüm genel ve korunan üyelere dayalı olarak oluşturulur. Bunlardan herhangi birini herhangi bir şekilde değiştirmek
serialVersionUID'u değiştirecektir. Dolayısıyla, yalnızca sınıfın birden fazla sürümünün serileştirilmeyeceğinden eminseniz (işlemler arasında veya daha sonraki bir zamanda depolama alanından alınan), bunlarla uğraşmanıza gerek kalmaz.
Şimdilik onları görmezden gelirseniz ve daha sonra sınıfı bir şekilde değiştirmeniz, ancak sınıfın eski sürümleriyle uyumluluğu korumanız gerektiğini öğrenirseniz, oluşturmak için JDK aracını serialver kullanabilirsiniz. eski sınıfındaki
serialVersionUID ve açıkça yeni sınıfa ayarlandı. (bağlıDeğişikliklerinizde ayrıca
serialVersionUID ve
writeObject yöntemleri ekleyerek özel serileştirme uygulamanız gerekebilir - bkz.
readObject javadoc veya yukarıda belirtilen bölüm 11.)
Eclipse'e şu serialVersionUID uyarılarını yoksaymasını söyleyebilirsiniz:
Pencere > Tercihler > Java > Derleyici > Hatalar /Uyarılar > Potansiyel Programlama Problemleri
Bilmemeniz durumunda, bu bölümde etkinleştirebileceğiniz birçok uyarı var (veya bazıları hata olarak bildirilmiş olsa bile), çoğu çok yararlıdır:
- Potansiyel Programlama Problemleri: Muhtemel yanlışlıkla boole ataması
- Potansiyel Programlama Sorunları: Boş işaretçi erişimi
- Gereksiz kod: Yerel değişken asla okunmaz
- Gereksiz kod: Yedekli null onay
- Gereksiz kod: Gereksiz yayın veya 'instanceof'
ve daha fazlası.
Serializable, seri hale getirilmiş verilerin sürümlendirilmesini kolaylaştırır. Serileştirme sırasında değeri verilerle birlikte kaydedilir. Serileştirme işleminde, serileştirilmiş verinin geçerli kodla nasıl eşleştiğini görmek için aynı sürüm denetlenir.
Verilerinizi sürümlendirmek istiyorsanız, normal olarak
serialVersionUID/0 ile başlar ve serileştirilmiş verileri değiştiren (geçici olmayan alanlar ekleyerek veya kaldırarak) sınıfınızdaki her yapısal değişiklikle çarpın.
Yerleşik seri hale getirme mekanizması (
serialVersionUID), sıfırdan seri hale getirilmeyi reddeder.Verilerin ld sürümleri. Ancak isterseniz, kendi readObject () - eski verileri geri okuyabilen bir işlev. Bu özel kod daha sonra
in.defaultReadObject()'u kontrol ederek verilerin hangi versiyonda olduğunu bilmek ve nasıl seri hale getirileceğine karar vermek için kontrol edebilir. Bu sürüm oluşturma tekniği, kodunuzun birkaç sürümünde hayatta kalan serileştirilmiş verileri saklarsanız kullanışlıdır.
Ancak seri hale getirilmiş verileri bu kadar uzun bir süre boyunca saklamak çok yaygın değildir. Seri hale getirme mekanizmasını, örneğin bir önbelleğe geçici olarak veri yazmak veya ağ üzerinden kod tabanının ilgili bölümlerinin aynı sürümüne sahip başka bir programa göndermek için kullanmak çok daha yaygındır.
Bu durumda geriye dönük uyumluluğu korumakla ilgilenmiyorsunuz. Yalnızca iletişimde bulunan kod tabanlarının, ilgili sınıfların aynı sürümlerine sahip olduğundan emin olmakla ilgileniyorsunuz. Böyle bir kontrolü kolaylaştırmak için,
serialVersionUID'u aynen önceki gibi tutmalı ve sınıflarınızda değişiklik yaparken güncellemeyi unutmamalısınız.
Alanı güncellemeyi unutursanız, farklı bir yapıya sahip ancak aynı
serialVersionUID'lu bir sınıfın iki farklı sürümüyle bitebilirsiniz. Bu olursa, varsayılan mekanizma (
serialVersionUID) herhangi bir fark algılamaz ve uyumsuz verileri seri hale getirmeye çalışır. Şimdi kriptik bir çalışma zamanı hatası veya sessiz hatayla (boş alanlar) bitebilir. Bu tür hataları bulmak zor olabilir.
Bu nedenle, bu kullanım tabanına yardımcı olmak için Java platformu,
in.defaultReadObject()'u el ile ayarlamama seçeneği sunar. Bunun yerine, derleme zamanında sınıf yapısının bir karması üretilecek ve id olarak kullanılacaktır. Bu mekanizma, aynı kimliğe sahip farklı sınıf yapılarına sahip olmadığınızdan emin olacak ve bu nedenle izlemesi zor olan çalışma zamanı serileştirme hatalarını yukarıda belirtmeyeceksiniz.
Ancak otomatik olarak oluşturulan kimlik stratejisinin arka tarafı vardır. Yani, aynı sınıf için üretilen kimlikleri derleyiciler arasında farklılık gösterebilir (yukarıda Jon Skeet tarafından belirtildiği gibi). Bu nedenle seri hale getirilmiş verileri farklı derleyicilerle derlenmiş kodlar arasında iletirseniz, kimlikleri yine de manuel olarak tutmanız önerilir.
Söz konusu ilk kullanım durumundaki gibi verilerinizle geriye dönük olarak uyumluysanız, muhtemelen kimliği de korumak istersiniz. Bu, okunabilir kimlikleri elde etmek ve ne zaman ve nasıl değiştikleri üzerinde daha fazla kontrol sahibi olmak için.
serialVersionUID nedir ve neden kullanmalıyım?
serialVersionUID iHer sınıf için benzersiz bir tanımlayıcı olan
SerialVersionUID, aynı sınıfın Serileştirme sırasında kullanıldığından emin olmak için sınıfın sürümlerini karşılaştırmak için bunu kullanır.
Birini belirtmek daha fazla kontrol sağlar; ancak siz belirtmezseniz JVM bir tane üretiyor. Üretilen değer, farklı derleyiciler arasında farklılık gösterebilir. Dahası, bazen sadece eski serileştirilmiş nesnelerin seri hale getirilmesini yasaklamak için bir sebepten istersiniz [
JVM] ve bu durumda serialVersionUID değerini değiştirmelisiniz.
varsayılan serialVersionUID hesaplaması sınıfa çok duyarlıdır derleyici uygulamalarına bağlı olarak değişebilen detaylar ve bu nedenle beklenmedik
Serializables sırasında seri kaldırma.
Bu nedenle, bize daha fazla kontrol sağladığı için serialVersionUID'yi bildirmelisiniz .
Bu makalenin konuyla ilgili bazı iyi noktaları vardır.
Orijinal soru,
serialVersionUID’un faydalı olacağı why neden bu kadar önemli ’ve“ örnek ”diye sordu. Bir tane buldum.
Serial Version ID sınıfı oluşturduğunuzu, başlattığınızı ve bir nesne akışına yazdığınızı söyleyin. Düzleştirilmiş araba nesnesi bir süre dosya sisteminde oturur. Bu arada,
Car sınıfı yeni bir alan eklenerek değiştirilirse. Daha sonra, düzleştirilmiş
Car nesnesini okumaya (yani seri hale getirmeye) çalıştığınızda,
Car'u elde edersiniz - çünkü tüm serileştirilebilir sınıflara otomatik olarak benzersiz bir tanımlayıcı verilir. Bu istisna, sınıfın tanımlayıcısı düzleştirilmiş nesnenin tanımlayıcısına eşit olmadığında atılır. Gerçekten düşünürseniz, yeni alanın eklenmesi nedeniyle istisna atılır. Açık bir serialVersionUID bildirerek, sürümünüzü kendiniz kontrol ederek bu istisnanın ortaya çıkmasını önleyebilirsiniz. Ayrıca,
java.io.InvalidClassException'unuzu açıkça beyan etmek için küçük bir performans avantajı vardır (çünkü hesaplanması gerekmez). Bu nedenle, kendi serialVersionUID'nizi, aşağıda gösterildiği gibi oluşturduğunuz gibi Serileştirilebilir sınıflarınıza eklemek en iyi yöntemdir:
serialVersionUID
Nesnelerinizi asla bayt dizisi için seri hale getirmeniz ve onları göndermeniz /kaydetmeniz gerekmiyorsa, endişelenmenize gerek yoktur. Bunu yaparsanız, o zaman serialVersionUID adresinizi göz önünde bulundurmalısınız, çünkü nesnenin seri hale getiricisi onu sınıf yükleyicisinin sahip olduğu nesne sürümüyle eşleştirecektir. Java Dil Özellikleri'nde bunun hakkında daha fazla bilgi edinin.
Eğer bu sınıfa seri hale getirme hakkında düşünmediğiniz ve kendinizi
1 ilan etmediğiniz bir uyarı alırsanız, bunun nedeni genellikle Serializable'ı uygulayan bir üst sınıftan miras almanızdır. Çoğu zaman, devralma kullanmak yerine böyle bir nesneye yetki vermek daha iyi olur.
Öyleyse,yerine
implements Serializable
do
public class MyExample extends ArrayList<String> { public MyExample() { super(); } ... }
ve ilgili yöntemlerde
(veya
public class MyExample { private List<String> myList; public MyExample() { this.myList = new ArrayList<String>(); } ... }
myList.foo()) yerine
this.foo()'u arayın. (Bu, tüm durumlara uymuyor ancak yine de oldukça sık.)
Sık sık JFrame'i ya da böyle bir şeyi genişleten insanları görürüm. (Bu aynı zamanda bir IDE'de otomatik tamamlamaya da yardımcı olur, çünkü JFrame sınıfınızdaki özel olanları aramak istediğinizde gerekmeyen yüzlerce yönteme sahiptir.)
Uyarının (veya serialVersionUID) kaçınılmaz olduğu bir durum, normal olarak anonim bir sınıfta AbstractAction'dan genişlettiğinizde, yalnızca actionPerformed yöntemini eklemenizdir. Bu durumda bir uyarı olmamasını düşünüyorum (normalde sınıfınızın farklı sürümlerinde bu tür anonim sınıfları güvenilir bir şekilde serileştiremez ve seri hale getiremezsiniz), ancak derleyicinin bunu nasıl tanıyabileceğinden emin değilim. p>
serialSversionUID alanın önemini anlamak için, Serileştirme /Serileştirmenin nasıl çalıştığını anlamak gerekir.
Seri hale getirilebilir bir sınıf nesnesi serileştirildiğinde Java Runtime, seri hale getirilmiş seri numarasını (serialVersionUID olarak adlandırılır) bu serileştirilmiş nesneyle ilişkilendirir. Bu serileştirilmiş nesneyi serileştirdiğinizde, Java Runtime, serileştirilmiş nesnenin serialVersionUID'sini sınıfın serialVersionUID ile eşleştirir. Eğer her ikisi de eşitse, sadece başka bir seriyi silme süreci devam ederse, başka InvalidClassException.
Bu nedenle, Serileştirme /Serileştirme işlemini başarılı kılmak için, serileştirilmiş nesnenin serialVersionUID değerinin, sınıfın serialVersionUID değerine eşit olması gerektiği sonucuna vardık. Programcının programda serialVersionUID değerini açıkça belirtmesi durumunda, aynı değer serileştirme ve serileştirme platformundan bağımsız olarak serileştirilmiş nesne ve sınıfla ilişkilendirilir (örneğin serileştirme için güneş pencereleri kullanılarak platformlar veya pencereler kullanılarak platformda yapılabilir. MS JVM ve Serileştirme, Zing JVM kullanarak farklı platformlarda Linux'ta olabilir).
Ancak serialVersionUID programlayıcı tarafından belirtilmezse, o zaman herhangi bir nesnenin Seriizasyonu \DeSerializasyonu yapılırken, Java çalışma zamanı hesaplamak için kendi algoritmasını kullanır. Bu serialVersionUID hesaplama algoritması bir JRE'den diğerine değişir. Nesnenin serileştirildiği ortamın bir JRE (örn: SUN JVM) kullanıyor olması ve seri kaldırma işleminin gerçekleştiği ortamın Linux Jvm (zing) kullanılması da mümkündür. Bu gibi durumlarda, serileştirilmiş nesneyle ilişkili serialVersionUID, seri kaldırma ortamında hesaplanan sınıfın serialVersionUID değerinden farklı olacaktır. Sırasıyla seri kaldırma başarılı olamayacak. Bu nedenle, bu tür durumlardan /sorunlardan kaçınmak için programcı her zaman Serializable sınıfının serialVersionUID'sini belirtmelidir.
Öncelikle serileştirmeyi açıklamam gerekiyor.
Serileştirme , nesneyi ağ üzerinden göndermek için nesnenin akışa dönüştürülmesini sağlar VEYA Dosyaya kaydet VEYA DB'ye kaydetmektup kullanımı için.
Serileştirme için bazı kurallar var .
-
Bir nesne, yalnızca sınıfı veya üst sınıfı Serileştirilebilir arabirimini uygularsa serileştirilebilir
-
Bir nesne, üst sınıfı olmasa bile serileştirilebilir (Serileştirilebilir arabirimi uygular). Bununla birlikte, seri hale getirilebilir sınıfın hiyerarşisinde, seri hale getirilebilir bir arabirim uygulamamış ilk üst sınıf, bağımsız bir yapıcıya sahip olmamalıdır. Bu ihlal edilirse, readObject () çalışma zamanında bir java.io.InvalidClassException oluşturacaktır
-
Tüm ilkel türler seri hale getirilebilir.
-
Geçici alanlar (geçici değiştiricili) seri hale getirilmedi (yani kaydedilmedi veya geri yüklenmedi). Serileştirilebilir uygulayan bir sınıf, serileştirmeyi desteklemeyen geçici sınıf alanlarını işaretlemelidir (örneğin, bir dosya akışı).
-
Statik alanlar (statik değiştiriciyle) serileştirilmedi.
Nesne Serileştirildiğinde JAVA Runtime, serialVersionID adı verilen seri sürüm numarasını ilişkilendirir.
serialVersionID: \em> 'e ihtiyaç duyduğumuz yerde: Göndericinin ve alıcının serileştirme ile uyumlu olduğunu doğrulamak için seri kaldırma sırasında. InvalidClassCastException ile.
Serileştirilebilir bir sınıf, statik, final ve uzun olması gereken "serialVersionUID" adlı bir alanı bildirerek kendi serialVersionUID değerini açıkça belirtebilir:
Bunu bir örnekle deneyelim.
__AUTOLOAD
Serileştirme Nesnesi Oluştur
import java.io.Serializable; public class Employee implements Serializable { private static final long serialVersionUID = 1L; private String empname; private byte empage; public String getEmpName() { return name; } public void setEmpName(String empname) { this.empname = empname; } public byte getEmpAge() { return empage; } public void setEmpAge(byte empage) { this.empage = empage; } public String whoIsThis() { StringBuffer employee = new StringBuffer(); employee.append(getEmpName()).append(" is ).append(getEmpAge()).append(" years old ")); return employee.toString(); } }
Nesneyi Deserializ
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; public class Writer { public static void main(String[] args) throws IOException { Employee employee = new Employee(); employee.setEmpName("Jagdish"); employee.setEmpAge((byte) 30); FileOutputStream fout = new FileOutputStream("/users/Jagdish.vala/employee.obj"); ObjectOutputStream oos = new ObjectOutputStream(fout); oos.writeObject(employee); oos.close(); System.out.println("Process complete"); } }
NOT: Şimdi Çalışan sınıfının serialVersionUID değerini değiştirin ve kaydedin:
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; public class Reader { public static void main(String[] args) throws ClassNotFoundException, IOException { Employee employee = new Employee(); FileInputStream fin = new FileInputStream("/users/Jagdish.vala/employee.obj"); ObjectInputStream ois = new ObjectInputStream(fin); employee = (Employee) ois.readObject(); ois.close(); System.out.println(employee.whoIsThis()); } }
Ve Reader sınıfını yürütün. Writer sınıfını çalıştırmak için değil ve istisna alacaksınız.
private static final long serialVersionUID = 4L;
Rahatsız etmeyin, varsayılan hesaplama gerçekten iyidir ve vakaların% 99,9999'u için yeterlidir. Sorun yaşarsanız, daha önce de belirtildiği gibi UID'leri ihtiyaç duyulduğu gibi sunabilirsiniz (ki bu pek olası değildir)
Eksik serialVersionUID öğesinin soruna neden olabileceği bir örnek için:
modül kullanan bir Web modülünden oluşan bu Java EE uygulaması üzerinde çalışıyorum. Web modülü
Exception in thread "main" java.io.InvalidClassException: com.jagdish.vala.java.serialVersion.Employee; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 4 at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:616) at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1623) at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1518) at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1774) at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1351) at java.io.ObjectInputStream.readObject(ObjectInputStream.java:371) at com.krishantha.sample.java.serialVersion.Reader.main(Reader.java:14)
EJBmodülünü uzaktan çağırır ve
EJB'u argüman olarak uygulayan bir
POJO'dan geçer.
Bu
Serializable sınıfı, EJB kavanozunun içinde ve web modülünün WEB-INF /lib'sinde kendi kavanozunun içinde paketlenmiştir. Onlar aslında aynı sınıftır, ancak EJB modülünü paketlediğimde, bu POJO'nun kavanozunu EJB modülü ile birlikte paketlemek için paketinden çıkardım.
POJO's’a yapılan çağrı aşağıdaki İstisna ile başarısız oldu çünkü
EJB’u ilan etmedim:
serialVersionUID
Genel olarak
'u bir bağlamda kullanırım: Bildiğimde Java VM'nin içeriğinden çıkacağını biliyorum.
Caused by: java.io.IOException: Mismatched serialization UIDs : Source (Rep. IDRMI:com.hordine.pedra.softbudget.domain.Budget:5CF7CE11E6810A36:04A3FEBED5DA4588) = 04A3FEBED5DA4588 whereas Target (Rep. ID RMI:com.hordine.pedra.softbudget.domain.Budget:7AF5ED7A7CFDFF31:6227F23FA74A9A52) = 6227F23FA74A9A52
Uygulamam için
serialVersionUID ve
ObjectInputStream kullandığımda ya da kullandığım bir kütüphane /çerçevenin kullanacağını bildiğimde bunu biliyordum. SerialVersionID, farklı sürümlerdeki veya satıcılardan oluşan farklı Java VM'lerinin doğru şekilde çalışmasını sağlar veya VM'in dışında depolanır ve alınırsa, örneğin
ObjectOutputStream, oturum verileri uygulama sunucusunun yeniden başlatılması ve yükseltilmesi sırasında bile kalabilir.
Diğer tüm durumlar için kullanıyorum
HttpSession
çoğu zaman varsayılan
yeterlidir. Bu,
@SuppressWarnings("serial")
serialVersionUID,
Exception’u içerir.
Alan verileri, sınıfta depolanan bazı bilgileri temsil eder.
Sınıf
HttpServlet arabirimini uygular,
böylece tutulma otomatik olarak
Serializable alanını bildirmeyi teklif etti. Burada ayarlanan 1 değeriyle başlayalım.
Bu uyarının gelmesini istemiyorsanız, şunu kullanın:
serialVersionUID
SerialVersionUID, nesnenin sürüm kontrolü için kullanılır. Ayrıca seri dosyanızda serialVersionUID değerini belirleyebilirsiniz. SerialVersionUID belirtmemenin sonucu, sınıfta herhangi bir alan eklediğinizde veya değiştirdiğinizde, o zaman zaten seri hale getirilmiş sınıf, yeni sınıf ve eski serileştirilmiş nesne için oluşturulan serialVersionUID farklı olacağından kurtarılamaz. Java serileştirme işlemi, serileştirilmiş nesnenin durumunu kurtarmak için doğru serialVersionUID değerine dayanır ve serialVersionUID uyuşmazlığı durumunda java.io.InvalidClassException öğesini atar
Daha fazla bilgi edinin: http://javarevisited.blogspot.com/2011/04 /üst-10-java-serileştirme-interview.html # ixzz3VQxnpOPZ
CheckStyle, Serializable'ı uygulayan bir sınıftaki serialVersionUID'in iyi bir değere sahip olduğunu, yani seri sürüm kimliği üretecinin üreteceği değerle eşleştiğini doğrularsa iyi olurdu. Çok fazla sayıda seri hale getirilebilen DTO'lu bir projeniz varsa, örneğin, mevcut serialVersionUID'yi silip yeniden oluşturmayı hatırlamak bir acıdır ve şu anda bunu doğrulamanın tek yolu her sınıf için yeniden oluşturmak ve karşılaştırmaktır. eski olan. Bu çok çok acı verici.
Neden Java'da
serialVersionUID sınıfı içinde
SerialVersionUID kullanıyorsunuz?
Serializable sırasında, Java çalışma zamanı bir sınıf için sürüm numarası oluşturur, böylece daha sonra seri hale getirilebilir. Bu sürüm numarası Java'da
serialization olarak bilinir.
SerialVersionUID, serileştirilmiş verileri sürümlendirmek için kullanılır. Bir sınıfı yalnızca serileştirilmiş örnekle
SerialVersionUID eşleşmesi durumunda serileştirebilirsiniz.
SerialVersionUID'u sınıfımızda ilan etmediğimizde, Java çalışma zamanı onu bizim için oluşturur, ancak önerilmez. Varsayılan mekanizmayı önlemek için
SerialVersionUID'u
SerialVersionUID değişken olarak bildirmeniz önerilir.
private static final long işaretleme arabirimini uygulayarak bir sınıfı
Serializable olarak bildirdiğinizde, Java çalışma zamanı,
java.io.Serializable arabirimini kullanarak işlemi özelleştirmemiş olmanız koşuluyla, varsayılan Serileştirme mekanizmasını kullanarak bu sınıfın örneğini diske aktarır.
Eski sınıflarla uyumluluğu koruyarak ilk etapta serialVersionUID ayarlanmamış çok sayıda sınıfı değiştirmek istiyorsanız, IntelliJ Idea, Eclipse gibi araçlar rastgele sayılar ürettiğinden kısa bir süre için düşer ve tek seferde bir sürü dosya. Kolaylıkla serialVersionUID sorununu düzeltmek için aşağıdaki bash betiğini (Windows kullanıcıları için özür dilerim, bir Mac satın almayı veya Linux'a dönüştürmeyi düşünün) geldim:
Externalizable
bu betiği kaydettiğinizde, add_serialVersionUID.sh dosyasını size ~ /bin olarak söyleyin. Ardından Maven veya Gradle projenizin kök dizininde şöyle çalışın:
base_dir=$(pwd) src_dir=$base_dir/src/main/java ic_api_cp=$base_dir/target/classes while read f do clazz=${f//\//.} clazz=${clazz/%.java/} seruidstr=$(serialver -classpath $ic_api_cp $clazz | cut -d ':' -f 2 | sed -e 's/^\s\+//') perl -ni.bak -e "print $_; printf qq{%s\n}, q{ private $seruidstr} if /public class/" $src_dir/$f done
Bu .lst, serialVersionUID'yi aşağıdaki biçimde eklemek için java dosyalarının listesini içerir:
add_serialVersionUID.sh < myJavaToAmend.lst
Bu komut dosyası, kaputun altındaki JDK serialVer aracını kullanır. Bu yüzden $JAVA_HOME /bin'inizin PATH içinde olduğundan emin olun.
Bu soru Etkili Java'da Joshua Bloch tarafından çok iyi belgelenmiştir. Çok iyi bir kitap ve mutlaka okumak gerekir. Aşağıdaki nedenlerden bazılarını ana hatlarıyla açıklayacağım:
Serileştirme çalışma zamanı, serileştirilebilir her sınıf için Seri sürüm adı verilen bir sayı ile gelir. Bu sayı serialVersionUID olarak adlandırılır. Şimdi bu sayının arkasında biraz Matematik var ve sınıfta tanımlanan alanlara /yöntemlere dayanıyor. Aynı sınıf için her zaman aynı sürüm oluşturulur. Serileştirme sırasında bu numara, serileştirilmiş bir nesnenin göndericisinin ve alıcısının, serileştirmeyle uyumlu olan nesne için yüklü sınıflara sahip olduğunu doğrulamak için kullanılır. Alıcı, karşılık gelen gönderenin sınıfından farklı bir seri VersiyonUID'si olan nesne için bir sınıf yüklediyse, seriyi kaldırma işlemi InvalidClassException ile sonuçlanacaktır.
Sınıfın seri hale getirilebilir olması durumunda, bir alan ilan ederek kendi serialVersionUID'nizi de açıkça belirtebilirsinizstatik, final ve uzun olması gereken "serialVersionUID" olarak adlandırıldı. Çoğu IDE Eclipse gibi o uzun dize oluşturmanıza yardımcı olur.
Bir nesne her seri hale getirildiğinde, nesne, nesnenin sınıfı için bir sürüm numarasıyla damgalanır. Bu kimliğe serialVersionUID ve sınıf yapısı hakkındaki bilgilere dayanarak hesaplanır. Bir Çalışan sınıfı oluşturduğunuzu ve # 333 (JVM tarafından atanan) sürüm kimliğine sahip olduğunu varsayalım, Şimdi bu sınıfın nesnesini serileştireceğiniz zaman (Suppose Çalışan nesnesi), JVM UID'yi # 333 olarak atayacaktır.
Bir durumu göz önünde bulundurun - ileride sınıfınızı düzenlemeniz veya değiştirmeniz gerekir ve bu durumda değiştirdiğinizde, JVM ona yeni bir UID atar (Diyelim # 444). Şimdi çalışan nesnesini seri hale getirmeye çalıştığınızda, JVM serileştirilmiş nesnenin (Çalışan nesnesi) sürüm kimliğini (# 333), yani sınıf # 444 (değiştirildiğinden beri) ile karşılaştırır. Karşılaştırmada, JVM her iki versiyonun da UID'yi farklı bulacağını ve bu nedenle Serileştirmenin başarısız olacağını görecektir. Bu nedenle, her sınıf için serialVersionID, programcının kendisi tarafından tanımlanırsa. Sınıf gelecekte geliştirilse bile aynı olacaktır ve dolayısıyla JVM, sınıf değişse bile sınıfın her zaman seri hale getirilmiş nesne ile uyumlu olduğunu görecektir. Daha fazla bilgi için HEAD FIRST JAVA’nın 14. bölümüne bakın.
Basit Bir Açıklama:
-
Verileri seri hale getiriyor musunuz?
Serileştirme, temel olarak sınıf verilerini bir dosyaya /stream /etc dosyasına yazar. Seri hale getirme, bu verileri bir sınıfa geri okuyor.
-
Üretime girmeyi düşünüyor musunuz?
Yalnızca önemsiz /sahte verileri olan bir şeyi test ediyorsanız, endişelenmeyin (doğrudan serileştirmeyi test etmiyorsanız).
-
Bu ilk sürüm mü?
Öyleyse,
serialVersionUID'u ayarlayın.
-
Bu ikinci, üçüncü vb. prod versiyonudur mu?
Şimdi yaklaşık
serialVersionUID=1L'dan endişelenmeniz ve derinlemesine bakmanız gerekiyor.
Temel olarak, bir sınıfı güncellediğinizde sürümü doğru şekilde güncellemezseniz, yazmanız /okumanız gereken, eski verileri okumaya çalıştığınızda bir hata alırsınız.
Uzun lafın kısaca anlatılması için, bu alan serileştirilmiş verilerin doğru şekilde seri hale getirilip getirilemeyeceğini kontrol etmek için kullanılır. Seri hale getirme ve seri hale getirme, genellikle programın farklı kopyaları tarafından yapılır; örneğin, sunucu nesneyi dizeye, istemci ise dizeyi nesneye dönüştürür. Bu alan, her ikisinin de bu nesnenin ne olduğu hakkında aynı fikirde çalıştığını söyler. Bu alan şu durumlarda yardımcı olur:
-
programınızın farklı yerlerde birçok kopyası var (1 sunucu ve 100 istemci gibi). Nesnenizi değiştirirseniz, sürüm numaranızı değiştirir ve bu istemcileri güncellemeyi unutursanız, seri kaldırma yeteneğine sahip olmadığını bilir.
-
verilerinizi bir dosyada sakladınız ve daha sonra değiştirilmiş nesneyle programınızın güncellenmiş sürümüyle açmayı deneyin - sürümünüzü doğru tutarsanız bu dosyanın uyumlu olmadığını bilirsiniz
Ne zaman önemlidir?
En belirgin olanı - nesnenize bazı alanlar eklerseniz, eski sürümler bunları kullanamayacaklardır, çünkü bu alanların nesne yapılarında bulunmaması.
Daha az açık - Nesneyi seriden çıkardığınızda, dizede bulunmayan alanlar NULL olarak tutulur. Alanınızı nesnenizden kaldırdıysanız, eski sürümler bu alanı her zaman-NULL olarak tutacaktır; eski sürümler bu alandaki verilere dayanıyorsa, bu durum yanlış davranışa yol açabilir (herhangi bir şey için oluşturduysanız)sadece eğlence için değil :-))
Çok açık - Bazen bir alanın anlamına koyduğunuz fikri değiştirirsiniz. Örneğin, 12 yaşındayken "bisiklet" altında "bisiklet" demek istiyorsun, ama 18 yaşındayken "motosiklet" demek istiyorsun - eğer arkadaşların seni "şehir içinde bisiklete binmeye" davet ederse ve bisikletle çıktığınızda, alanlar arasında aynı anlamı korumanın ne kadar önemli olduğunu anlayacaksınız :-)
Öncelikle sorunuzu yanıtlamak için, sınıfımızda SerialVersionUID bildirmediğimizde, Java çalışma zamanı bizim için üretir, ancak bu işlem alan sayısı, alanların türü, alanların erişim değiştiricisini içeren birçok sınıf meta verisine duyarlıdır , arayüz sınıf tarafından uygulanan vb. Bu nedenle, kendimizi açıklamamız önerilir ve Eclipse sizi aynı konuda uyarıyor.
Serile: Sık sık, durumu (nesnenin değişkenlerindeki veriler) o kadar önemli olan önemli nesnelerle çalışırız ki, nesnenin durumunu diğer makineye göndermesi durumunda güç /sistem arızası (veya) ağ arızası nedeniyle kaybetme riskini alamayız. Bu problemin çözümü, "Kalıcılık" olarak adlandırılır ve bu, verilerin kalıcı olarak (bekletilmesi /kaydedilmesi) anlamına gelir. Seri hale getirme, kalıcılık elde etmenin birçok yolundan biridir (verileri diske /belleğe kaydederek). Nesnenin durumunu kaydederken, nesneyi uygun bir şekilde tekrar okuyabilmek için (seri hale getirme) bir kimlik oluşturmak önemlidir. Bu benzersiz kimlik, ID ise SerialVersionUID'dir.
serialVersionUID