Java neden Serileştirilebilir arayüze ihtiyaç duyar?


114

Yoğun bir şekilde serileştirme ile çalışıyoruz ve kullandığımız her nesnede Serileştirilebilir etiket belirtmek zorunda kalmak bir tür külfettir. Özellikle de gerçekten değiştiremeyeceğimiz bir 3. parti sınıf olduğunda.

Soru şu: Serializable boş bir arayüz olduğundan ve Java eklediğinizde sağlam serileştirme sağladığından implements Serializable- neden her şeyi serileştirilebilir hale getirmediler ve bu kadar?

Neyi kaçırıyorum?


Ya kendi nesnenizi Seri hale getirilebilir yapmak istiyorsanız? Yoksa bir şeyi yanlış mı anladım?
Joe Phillips

Nesnelerimin tüm alanlarının serileştirilebilir olması gerektiğinden NotSerializableException almaya devam edeceğim
Yoni Roit

Pop Catalin ve Dmitry'nin "Bu Serileştirilebilir numara, on ya da iki yıl önce alınmış bir başka yanlış karardır" ile tamamen aynı fikirde. Serileştirmenin ne kadar tehlikeli olabileceği önemli değil. Ve beyan açık olduğundan "özel dikkat göstermeniz gerektiğini bilirsiniz": buna ihtiyacı olan herkes önce "uygular" şeyler koyar ve sonra bir şeyler ters giderse imalar hakkında düşünür. Bize özel durumlarda uygulanmak üzere "Serileştirilemez" bir arayüz verseler daha net olabilirdi.
Jack

Yanıtlar:


120

Serileştirme tuzaklarla doludur. Bu formun otomatik serileştirme desteği, sınıf içlerini genel API'nin bir parçası haline getirir (bu nedenle javadoc size sınıfların kalıcı formlarını verir ).

Uzun vadeli kalıcılık için, sınıfın bu formu çözebilmesi gerekir, bu da sınıf tasarımında yapabileceğiniz değişiklikleri kısıtlar. Bu, kapsüllemeyi bozar.

Serileştirme ayrıca güvenlik sorunlarına da yol açabilir. Başvurusu olan herhangi bir nesneyi seri hale getirerek, bir sınıf normalde erişemeyeceği verilere erişebilir (ortaya çıkan bayt verilerini ayrıştırarak).

İyi tanımlanmayan iç sınıfların serileştirilmiş biçimi gibi başka sorunlar da vardır.

Tüm sınıfları serileştirilebilir yapmak, bu sorunları daha da kötüleştirir. Check Etkili Java ikinci sürüm , özellikle Madde 74: SERIALIZABLE mantıklı uygulamak .


2
Açıkça daha iyi cevap bu, seçilen cevabın bu olmadığı için hayal kırıklığına uğradım, görünen o ki, "Sinirlendim çünkü her şeyi serileştirilebilir ilan etmem gerekiyor" gündemiyle seçti. Bu, geçmişte öğrenilmiş olan güvenlik ve tasarım derslerine aldırış etmeden serbest kalmayı isteyen birinin örneğidir.
gbtimmon

@McDowell Kalıcı sınıf biçimleriyle neyi kastediyorsunuz? Bu bağlantıyı takip ettim ama ne demek istediğini anlayamıyorum? bunu açıklar mısın lütfen
Geek

@Geek - URL türünün serileştirilmiş formu (örneğin), türün hangi özel alanlara sahip olması gerektiğini ve bunların hangi sırada bildirilmesi gerektiğini tanımlar.
McDowell

@McDowell Sipariş neden önemli?
Geek

12
@McDowell Merhaba. Ben 4 yıl öncesinden bu sorunun orijinal göndericisiyim ve eğer bir anlamı varsa, cevabınızı kabul edildi olarak seçtim. Cevabınızın gerçekten daha iyi olduğunu düşünüyorum ve muhtemelen o zaman bu şekilde göremeyecek kadar olgunlaşmamıştım. Şimdi
tamir ediyorum

32

Bence hem Java hem de .Net çalışanları bu sefer yanlış anladılar, her şeyi varsayılan olarak serileştirilebilir hale getirmek daha iyi olurdu ve bunun yerine güvenli bir şekilde serileştirilemeyen sınıfları işaretlemeleri yeterli olurdu.

Örneğin Smalltalk'ta (70'lerde oluşturulan bir dil) her nesne varsayılan olarak serileştirilebilir. Nesnelerin büyük çoğunluğunun serileştirmek için güvenli olduğu ve sadece birkaçının güvenli olmadığı gerçeğini göz önünde bulundurarak, Java'da neden böyle olmadığı hakkında hiçbir fikrim yok.

Bir nesneyi serileştirilebilir olarak (bir arayüzle) işaretlemek, o nesneyi sihirli bir şekilde serileştirilebilir yapmaz, baştan sona serileştirilebilirdi , sadece şimdi sistemin kendi başına bulabileceği bir şeyi ifade ettiniz, bu yüzden gerçekten iyi bir neden göremiyorum serileştirme şimdi olduğu gibi.

Bence bu ya tasarımcılar tarafından alınan kötü bir karardı ya da serileştirme sonradan düşünüldü ya da platform hiçbir zaman varsayılan olarak tüm nesnelerde güvenli ve tutarlı bir şekilde serileştirme yapmaya hazır değildi.


26
Örneklerin mantıklı bir şekilde serileştirilmesini sağlamak için bir sınıf tasarlarken ve uygularken özel dikkat göstermeniz gerekir. Serileştirilebilir arayüz aslında şu anlama gelir: "Ben, bir programcı olarak, serileştirmenin sonuçlarını anladım ve
JVM'nin

@Rolf Rander: Çoğu zaman hiç ilgilenmenize gerek yoktur, sadece serileştirilebilir sınıfı işaretleyin. Serileştirme tüm nesnelerde varsayılan olarak AÇIK olsaydı, her geliştiricinin zihniyeti de farklı olurdu, bir sınıfı serileştirilebilir hale getirmek doğal bir şey olurdu ...
Pop Catalin

örneğin bellek sızıntısı olmadığından emin olmak gibi iyi sınıf tasarım listesine başka bir endişe daha ekleyebilirdi. Yine de, iyi sınıf tasarımı, sınıflarınızın mümkün olduğunda serileştirilebilir olmasını giderek daha fazla gerektirir.
Pop Catalin

3
@StaxMan, çünkü daha sonra bir sınıfı serileştirmeniz gerektiğini ve yapamayacağınızı fark etmek çok maliyetli olabilir. Fazladan az çabanın karşılığını aldığı durumlardan biri. Bu, özellikle bir kitaplık yazıyorsanız ve başka biri kaynak kodu olmadan onu kullanacaksa geçerlidir
Pop Catalin

2
Bu yanıta tamamen katılıyorum. Birçok dilde her şey varsayılan olarak serileştirilebilir. Ve aslında JVM ile aynıdır, çünkü özel olsun ya da olmasın herhangi bir sınıf üyesine erişmek için Reflection'ı kullanmak kolaydır. Bu Serializablenumara, on ya da iki yıl önce alınan bir başka yanlış karardır ve standart kitaplıktaki toplama ve dizgi işlemedeki bazı kusurlar gibi, saf java ile uğraşırken yaşanan sıkıntının bir ekidir. Ne mutlu ki Kryo var, ama bu bağımlılık ve önce onu bulmalıyız. Yerleşik serileştirmenin bu şekilde yapılması gerekirdi.
dmitry

20

Her şey gerçekten serileştirilemez. Örneğin bir ağ soketi bağlantısını ele alalım. Soket nesnenizin verilerini / durumunu seri hale getirebilirsiniz, ancak aktif bir bağlantının özü kaybolur.


Bu benim sorunum olurdu ve soketi serileştirmeye çalışacak kadar akıllı olmasaydım, hata ayıklama sırasında hatamı bulurdum. Ancak, Serializable'ı iyi bir neden olmadan uygulamayan 3. parti sınıf nedeniyle Java serileştirmeyi hiç kullanamadığım bir durumdayım.
Yoni Roit

4
Bu durumu ele almanın birkaç iyi yolu vardır, örneğin 3. parti sınıfın anahtar verilerini nasıl okuyup yazacağını bilen bir Serializable wrapper sınıfı yazmak; sarılmış örneği geçici hale getirin ve writeObject ve readObject öğelerini geçersiz kılın.
Greg Case

API'nizdeki gerekli nesnelerden miras alabilir ve bu sınıfları serileştirebilir misiniz?
Joel Coehoorn

@Joel: Bu iyi bir fikir, ama yine de bir hack. Sanırım tüm bunlar başka bir değiş tokuşun ters gitti. Yorumlarınız için teşekkürler.
Yoni Roit

1
Bu, gerçekten ihtiyacımız olan tek şeyin olduğunu gösteren nadir örneklerden biridir implements NotSerializable:)
Rob Grant

13

Java'da Serializable'ın ana rolü, varsayılan olarak diğer tüm nesneleri serileştirilemez hale getirmektir. Serileştirme, özellikle varsayılan uygulamasında çok tehlikeli bir mekanizmadır. Bu nedenle, C ++ 'daki arkadaşlık gibi, işleri serileştirilebilir hale getirmek biraz maliyetli olsa bile, varsayılan olarak kapalıdır.

Serileştirme, yapı uyumluluğu sigortalanmadığı için kısıtlamalar ve olası sorunlar ekler. Varsayılan olarak kapalı olması iyidir.

Standart serileştirmenin istediğimi yaptığı çok az önemsiz sınıf gördüğümü itiraf etmeliyim. Özellikle karmaşık veri yapıları durumunda. Dolayısıyla, sınıfı serileştirmek için harcayacağınız çaba, arayüzü eklemenin maliyetini gölgede bırakır.


9

Bazı sınıflar için, özellikle bir Dosya, Soket, İş Parçacığı veya DB bağlantısı gibi daha fiziksel bir şeyi temsil edenler için, örnekleri serileştirmenin kesinlikle bir anlamı yoktur. Diğerleri için Serileştirme sorunlu olabilir çünkü benzersizlik kısıtlamalarını ortadan kaldırır veya sizi bir sınıfın farklı sürümlerinin örnekleriyle uğraşmaya zorlar, ki bunu istemeyebilirsiniz.

Muhtemelen, her şeyi varsayılan olarak Seri hale getirilebilir yapmak ve sınıfları bir anahtar kelime veya işaretleyici arabirimi aracılığıyla serileştirilemez hale getirmek daha iyi olabilirdi - ancak o zaman bu seçeneği kullanması gerekenler muhtemelen bunu düşünmezler. Öyle ki, Seri hale getirilebilir uygulamanız gerekiyorsa, size bir İstisna ile söylenecektir.


4

Sanırım bu, programcı olarak, nesnenizin benim serileştirilmesini bildiğinizden emin olmaktı.



1

Belli bir sınıfın örneklerinin Seri hale getirilebilir olduğunu açıkça belirtmek zorunda, dil sizi buna izin vermeniz gerekip gerekmediğini düşünmeye zorluyor. Basit değerli nesneler için serileştirme önemsizdir, ancak daha karmaşık durumlarda gerçekten düşünmeniz gerekir.

Sadece JVM'nin standart serileştirme desteğine güvenerek, kendinizi her tür kötü sürüm oluşturma sorunuyla karşı karşıya bırakırsınız.

Benzersizlik, 'gerçek' kaynaklara yapılan atıflar, zamanlayıcılar ve diğer birçok yapay nesne türü serileştirme için aday DEĞİLDİR.



0

Pekala, cevabım, bunun iyi bir nedeni olmadığıdır. Ve yorumlarınızdan bunu zaten öğrendiğinizi görebiliyorum. Diğer diller siz 10'a kadar saydıktan sonra bir ağaca atlamayan her şeyi mutlu bir şekilde serileştirmeye çalışır. Bir Nesne varsayılan olarak serileştirilebilir olmalıdır.

Yani, temelde yapmanız gereken, 3. parti sınıfınızın tüm özelliklerini kendiniz okumaktır. Veya, bu sizin için bir seçenekse: derlemesini çözün, lanet anahtar kelimeyi oraya koyun ve yeniden derleyin.


2
Serileştirme, yapı uyumluluğu sigortalanmadığı için kısıtlamalar ve olası sorunlar ekler. IMHO, Varsayılan olarak kapalı olması iyidir.
Uri

"Yapı uyumluluğu" ile ne demek istediğinizden emin değilim.
nes1983

0

Java'da, çalışma zamanına özgü oldukları için serileştirilemeyen bazı şeyler vardır. Akışlar, iş parçacıkları, çalışma zamanı vb. Gibi şeyler ve hatta bazı GUI sınıfları (temeldeki işletim sistemine bağlı olan) serileştirilemez.


0

Buradaki diğer cevaplarda verilen noktalara katılıyorum, ancak asıl sorun serileştirmeyle ilgili: Sınıf tanımı değişirse, seriyi kaldırma işleminin işe yaramayacağı gerçek bir risk var. Mevcut alanları asla değiştirmemek, bir kitaplık yazarının yapması gereken oldukça büyük bir taahhüttür! API uyumluluğunu korumak, olduğu gibi bir angarya için yeterlidir.


Bu doğru değil. Burada iddia ettiğiniz şey doğruysa var olmayacak olan Nesne Serileştirilebilir Nesnelerin Sürümlendirilmesi bölümünü okumanız gerekir . Sınıf tanımı, önceki serileştirmelerle uyumsuz hale gelmeden önce oldukça geniş sınırlar içinde değişebilir. Ve kesinlikle sorunun cevabı değil. Gerçek neden güvenlik endişeleriyle ilgilidir.
Marquis of Lorne

@EJP, doğruluk adına cevabımı puanlarınızı yansıtacak şekilde düzenledim. Duygu devam ediyor, bu büyük bir taahhüt,
vazgeçmek

0

Bir dosyaya veya başka bir medyaya kalıcı olması gereken bir sınıfın Serializable arabirimi uygulaması gerekir, böylece JVM, sınıf nesnesinin serileştirilmesine izin verebilir. Neden Object sınıfı serileştirilmedi, bu durumda sınıfların hiçbirinin arabirimi uygulaması gerekmiyor, sonra tüm JVM sınıfı yalnızca ObjectOutputStream kullandığımda serileştiriyor, bu da JVM'nin serileştirmesine izin vermek için kontrolün hala benim elimde olduğu anlamına geliyor.

Nesne sınıfının varsayılan olarak serileştirilebilir olmamasının nedeni, ana sorun sınıf sürümünün olmasıdır. Bu nedenle, serileştirmeyle ilgilenen her sınıfın açıkça Serializable olarak işaretlenmesi ve bir serialVersionUID sürüm numarası sağlaması gerekir.

Eğer serialVersionUID JVM atar neden o zaman sağlanmaz nesneyi deserialzing ederken beklenmedik sonuçlar elde, yani InvalidClassException eğer serialVersionUID eşleşmiyor. Bu nedenle, her sınıfın Serializable arabirimi uygulaması ve her iki uçta sunulan Sınıfın aynı olduğundan emin olmak için serialVersionUID sağlaması gerekir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.