सीरियलवर्सनयूआईडी क्या है और मुझे इसका उपयोग क्यों करना चाहिए?


2997

serialVersionUIDगायब होने पर ग्रहण की चेतावनी जारी करता है।

क्रमबद्ध करने योग्य वर्ग फू लंबी अवधि के स्थिर अंतिम क्रमबद्ध धारावाहिक की घोषणा नहीं करता है

क्या है serialVersionUIDऔर यह क्यों महत्वपूर्ण है? कृपया एक उदाहरण दिखाएं जहां गुम होने serialVersionUIDसे समस्या होगी।


1
SerialversionUID के बारे में एक अच्छा अभ्यास प्राप्त करें; dzone.com/articles/what-is-serialversionuid
ceyun

जवाबों:


2289

डॉक्स के java.io.Serializableबारे में शायद उतना ही अच्छा स्पष्टीकरण है जितना आपको मिलेगा:

क्रमांकन रनटाइम प्रत्येक क्रमिक श्रेणी के साथ संबद्ध होता है एक संस्करण संख्या, जिसे एक कहा जाता है serialVersionUID, जिसका उपयोग यह सत्यापित करने के लिए किया जाता है कि क्रमबद्ध वस्तु के प्रेषक और रिसीवर ने उस वस्तु के लिए कक्षाएं लोड की हैं जो क्रमांकन के संबंध में संगत हैं। यदि रिसीवर ने उस ऑब्जेक्ट के लिए एक वर्ग लोड किया है serialVersionUIDजो संबंधित प्रेषक वर्ग की तुलना में अलग है, तो डिसेरलाइज़ेशन का परिणाम होगा InvalidClassException। एक क्रमबद्ध वर्ग serialVersionUIDस्पष्ट रूप से serialVersionUIDस्थिर, अंतिम और प्रकार का होना चाहिए, नाम से एक क्षेत्र घोषित करके अपनी खुद की घोषणा कर सकता है long:

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

यदि कोई धारावाहिक श्रेणी स्पष्ट रूप से घोषित नहीं करती है serialVersionUID, तो क्रमांकन रनटाइम serialVersionUIDउस वर्ग के लिए डिफ़ॉल्ट मान की गणना करेगा , जैसा कि जावा (टीएम) ऑब्जेक्ट सीरियलाइजेशन विनिर्देश में वर्णित है। हालांकि, यह दृढ़ता से अनुशंसा की जाती है कि सभी अनुक्रमिक वर्ग स्पष्ट रूप से serialVersionUIDमूल्यों की घोषणा करते हैं, क्योंकि डिफ़ॉल्ट serialVersionUIDगणना वर्ग के विवरण के प्रति अत्यधिक संवेदनशील है जो संकलक कार्यान्वयन के आधार पर भिन्न हो सकती है, और इस प्रकार InvalidClassExceptionsडिसेरिएलाइजेशन के दौरान अप्रत्याशित रूप से परिणाम हो सकता है । इसलिए, serialVersionUIDविभिन्न जावा कंपाइलर कार्यान्वयनों के अनुरूप मूल्य की गारंटी देने के लिए , एक श्रेणीबद्ध श्रेणी को एक स्पष्ट serialVersionUIDमूल्य घोषित करना चाहिए । यह भी स्पष्ट रूप से सलाह दी जाती हैserialVersionUIDघोषणाएं जहां संभव हो, निजी संशोधक का उपयोग करती हैं, क्योंकि ऐसी घोषणाएं केवल घोषित श्रेणी के serialVersionUIDक्षेत्रों पर ही लागू होती हैं, विरासत में मिले सदस्यों के रूप में उपयोगी नहीं हैं।


325
इसलिए, आप जो अनिवार्य रूप से कह रहे हैं, वह यह है कि यदि कोई उपयोगकर्ता उपरोक्त सभी सामग्रियों को नहीं समझता है, तो उपयोगकर्ता ने कहा कि क्रमिकता के बारे में चिंता करना परेशान नहीं करता है? मेरा मानना ​​है कि आपने "कैसे?" का उत्तर दिया। "क्यों?" समझाने के बजाय। मैं, एक के लिए, समझ में नहीं आता कि मैं SerializableVersionUID से परेशान क्यों हूं।
जिग्गी

365
दूसरे पैराग्राफ में क्यों है: यदि आप स्पष्ट रूप से सीरियलव्यूडयूआईडी निर्दिष्ट नहीं करते हैं, तो एक मूल्य स्वचालित रूप से उत्पन्न होता है - लेकिन यह भंगुर है क्योंकि यह कंपाइलर कार्यान्वयन पर निर्भर है।
जॉन स्कीट

14
और एक्लिप्स क्यों कहता है कि मुझे "निजी स्थिर अंतिम लंबे सीरियलव्यूड यूआईडी = 1 एल;" की आवश्यकता है जब मैं अपवाद कक्षा का विस्तार करूं?
जॉनमेरलिनो

21
@ जॉनमोर्लिनो: वैसे मैं यह अपेक्षा नहीं करूंगा कि आपको एक की आवश्यकता है - लेकिन यह अपवादों को सही ढंग से क्रमबद्ध करने में आपकी मदद करने के लिए एक सुझाव दे सकता है। यदि आप उन्हें क्रमबद्ध नहीं करने जा रहे हैं, तो आपको वास्तव में निरंतरता की आवश्यकता नहीं है।
जॉन स्कीट

16
@JohnMerlino, आप के सवाल का हिस्सा क्यों है, इसका उत्तर देने के लिए: अपवाद लागू होता है Serializable और ग्रहण चेतावनी देता है कि आपने एक serialVersionUID सेट नहीं किया है, जो एक अच्छा विचार होगा (यदि आप वर्ग को अनुक्रमित नहीं करना चाहते हैं), जो जॉनस्केट के पोस्ट से होने वाली समस्याओं से बचने के लिए। रूपरेखा।
zpon

475

यदि आप सिर्फ इसलिए इसे क्रमबद्ध कर रहे हैं, तो आपको कार्यान्वयन के लिए क्रमबद्ध करना होगा (यदि आप परवाह करते हैं कि आप किसके लिए क्रमबद्ध हैं HTTPSession, उदाहरण के लिए ... यदि यह संग्रहीत है या नहीं, तो आप शायद de-serializingकिसी फॉर्म ऑब्जेक्ट की परवाह नहीं करते हैं ), तो आप कर सकते हैं इस पर ध्यान मत दें।

यदि आप वास्तव में क्रमांकन का उपयोग कर रहे हैं, तो यह केवल तभी मायने रखता है जब आप सीधे क्रमांकन का उपयोग करके वस्तुओं को संग्रहीत करने और पुनः प्राप्त करने की योजना बनाते हैं। serialVersionUIDआपके वर्ग संस्करण का प्रतिनिधित्व करता है, और आपको इसे बढ़ाना चाहिए, यदि आपकी कक्षा का वर्तमान संस्करण अपने पिछले संस्करण के साथ पीछे की ओर संगत नहीं है।

ज्यादातर समय, आप शायद सीधे तौर पर क्रमांकन का उपयोग नहीं करेंगे। यदि यह स्थिति है, SerialVersionUIDतो त्वरित फिक्स विकल्प पर क्लिक करके एक डिफ़ॉल्ट उत्पन्न करें और इसके बारे में चिंता न करें।


78
मैं कहूंगा कि यदि आप स्थायी भंडारण के लिए क्रमांकन का उपयोग नहीं कर रहे हैं, तो आपको मूल्य जोड़ने के बजाय @SuppressWarnings का उपयोग करना चाहिए। यह वर्ग को कमतर कर देता है, और यह असंगत बदलावों से बचाने के लिए serialVersionUID तंत्र की संयमता को बनाए रखता है।
टॉम एंडरसन

25
मैं यह नहीं देखता कि एक पंक्ति (@SuppressWarnings एनोटेशन) को दूसरी पंक्ति (सीरियल आईडी) के विपरीत "क्लास कमज़ोर" कैसे जोड़ा जाए। और यदि आप स्थायी भंडारण के लिए क्रमांकन का उपयोग नहीं कर रहे हैं, तो आप "1" का उपयोग क्यों नहीं करेंगे? आप वैसे भी ऑटोजेनरेटेड आईडी की परवाह नहीं करेंगे।
MetroidFan2002

71
@ MetroidFan2002: मुझे लगता है कि serialVersionUIDअसंगत बदलावों से आपको बचाने के लिए टॉमएंडर्सन की बात वैध है। का उपयोग करते हुए @SuppressWarningsदस्तावेजों मंशा बेहतर आप स्थायी भंडारण के लिए वर्ग का उपयोग करने की इच्छा नहीं है।
अब्दुल्ला

11
"आपको अपनी कक्षा के वर्तमान संस्करण के पिछले संस्करण के साथ पीछे की ओर संगत नहीं होने पर इसे बढ़ाना चाहिए:" आपको पहले सीरियलाइज़ेशन के व्यापक समर्थन संस्करण का पता लगाना चाहिए, (क) यह सुनिश्चित करने के लिए कि कक्षा वास्तव में अब क्रमबद्धता-असंगत तरीका है। विनिर्देशन प्रति प्राप्त करना काफी कठिन है; (बी) एक योजना जैसे कि कस्टम रीड / राइटऑबजेक्ट () मेथड्स, readResolve / writeReplace () मेथड्स, सेरीटेबलफिल्ड्स डिक्लेरेशन आदि की कोशिश करें, ताकि यह सुनिश्चित हो सके कि स्ट्रीम संगत बनी हुई है। वास्तविक बदलना serialVersionUIDएक अंतिम उपाय है, निराशा का एक वकील।
user207421

4
@VJP वेतन वृद्धि serialVersionUID की तस्वीर में आती है जब वर्ग के प्रारंभिक लेखक ने स्पष्ट रूप से पेश किया है। मैं कहूंगा, जेवीएम उत्पन्न सीरियल आईडी, ठीक होना चाहिए। यह सबसे अच्छा जवाब है जो मैंने क्रमांकन पर देखा था।
ओवरएक्सचेंज

307

मैं इस अवसर को जोश बलोच की पुस्तक इफेक्टिव जावा (द्वितीय संस्करण) को प्लग करने का अवसर नहीं दे सकता । अध्याय 11 जावा क्रमांकन पर एक अपरिहार्य संसाधन है।

जोश के अनुसार, स्वचालित रूप से उत्पन्न यूआईडी एक वर्ग के नाम, कार्यान्वित इंटरफेस, और सभी सार्वजनिक और संरक्षित सदस्यों के आधार पर उत्पन्न होता है। इनमें से किसी भी तरह से बदलने से परिवर्तन होगा serialVersionUID। इसलिए आपको केवल उनके साथ गड़बड़ करने की आवश्यकता नहीं है यदि आप निश्चित हैं कि कक्षा के एक से अधिक संस्करण कभी भी क्रमबद्ध नहीं होंगे (या तो प्रक्रियाओं के दौरान या बाद में भंडारण से पुनर्प्राप्त किए गए)।

अब आप के लिए उन्हें अनदेखा हैं, और बाद में है कि आप किसी तरह से वर्ग बदल सकता है लेकिन अनुकूलता डब्ल्यू / वर्ग के पुराने संस्करण है, तो आप JDK उपकरण का उपयोग कर सकते हैं बनाए रखने की जरूरत को खोजने के serialver उत्पन्न करने के लिए serialVersionUIDपर वर्ष वर्ग, और स्पष्ट रूप से वह सेट नई कक्षा में। (अपने परिवर्तनों के आधार पर आपको जोड़कर writeObjectऔर readObjectतरीकों द्वारा कस्टम क्रमांकन भी लागू करने की आवश्यकता हो सकती है - Serializableजावदोक या उपर्युक्त अध्याय 11 देखें)


33
यदि एक वर्ग के अनुकूलता w / पुराने संस्करणों के बारे में चिंतित थे, तो कोई SerializableVersionUID से परेशान हो सकता है?
जिग्गी

10
हाँ, यदि नया संस्करण किसी भी सार्वजनिक सदस्य को संरक्षित करने के लिए बदलता है, तो डिफ़ॉल्ट SerializableVersionUID अलग होगा और एक InvalidClassException को बढ़ाएगा।
चंदर शिवदासानी

3
वर्ग का नाम, लागू इंटरफेस, सभी सार्वजनिक और संरक्षित तरीके, सभी उदाहरण चर।
अचोव

31
यह ध्यान देने योग्य है कि यहोशू बलोच ने सलाह दी है कि प्रत्येक धारावाहिक श्रेणी के लिए यह धारावाहिक संस्करण को निर्दिष्ट करने लायक है। अध्याय 11 से उद्धरण: आप जो भी क्रमबद्ध रूप चुनते हैं, उसके बावजूद, आपके द्वारा लिखे जाने वाले प्रत्येक धारावाहिक श्रेणी में एक स्पष्ट धारावाहिक संस्करण UID घोषित करें। यह असंगतता के संभावित स्रोत (आइटम 74) के रूप में सीरियल संस्करण यूआईडी को समाप्त करता है। एक छोटा प्रदर्शन लाभ भी है। यदि कोई सीरियल संस्करण यूआईडी प्रदान नहीं किया गया है, तो रनटाइम में एक को उत्पन्न करने के लिए एक महंगी गणना आवश्यक है।
आशुतोष जिंदल

136

आप ग्रहण को इन धारावाहिकों की अनदेखी के बारे में बता सकते हैं:

विंडो> प्राथमिकताएं> जावा> कंपाइलर> त्रुटियां / चेतावनी> संभावित प्रोग्रामिंग समस्याएं

यदि आप नहीं जानते हैं, तो बहुत सी अन्य चेतावनियाँ हैं जिन्हें आप इस खंड में सक्षम कर सकते हैं (या कुछ त्रुटियों के रूप में भी रिपोर्ट किया गया है), कई बहुत उपयोगी हैं:

  • संभावित प्रोग्रामिंग समस्याएं: संभावित आकस्मिक बूलियन असाइनमेंट
  • संभावित प्रोग्रामिंग समस्याएं: अशक्त सूचक पहुंच
  • अनावश्यक कोड: स्थानीय चर कभी नहीं पढ़ा जाता है
  • अनावश्यक कोड: अनावश्यक निरर्थक जाँच
  • अनावश्यक कोड: अनावश्यक कलाकारों या 'उदाहरण'

और बहुत सारे।


21
अपवाह लेकिन केवल इसलिए कि मूल पोस्टर कुछ भी प्रसारित नहीं करता है। अगर पोस्टर ने कहा, "मैं इस बात को क्रमबद्ध कर रहा हूं और ..." तो आपको इसके बजाय एक वोट मिलेगा: P
जॉन गार्डनर

3
यह सच है - मैं मान रहा था कि प्रश्नकर्ता केवल चेतावनी नहीं देना चाहता था
मैट बी

14
@ गार्डनर -> सहमत! लेकिन प्रश्नकर्ता यह भी जानना चाहता है कि वह क्यों नहीं चेतावनी देना चाहता है।
जिग्गी

8
प्रश्नकर्ता स्पष्ट रूप से परवाह करता है कि यूआईडी क्यों होना चाहिए। तो बस उसे चेतावनी को नजरअंदाज करने के लिए कह देना चाहिए।
CinqS

111

serialVersionUIDक्रमबद्ध डेटा के संस्करण की सुविधा। सीरियल करते समय इसका मान डेटा के साथ संग्रहीत किया जाता है। जब डी-क्रमांकन किया जाता है, तो उसी संस्करण की जांच की जाती है कि धारावाहिक डेटा वर्तमान कोड से कैसे मेल खाता है।

यदि आप अपना डेटा संस्करण में लाना चाहते हैं, तो आप सामान्य रूप serialVersionUIDसे 0 से शुरू करते हैं , और इसे अपनी कक्षा में हर संरचनात्मक परिवर्तन से जोड़ते हैं, जो क्रमबद्ध डेटा (गैर-क्षणिक क्षेत्रों को जोड़ने या हटाने) को बदल देता है।

अंतर्निहित डी-क्रमांकन तंत्र ( in.defaultReadObject()) डेटा के पुराने संस्करणों से डी-सीरीज़ करने से इनकार कर देगा। लेकिन अगर आप चाहते हैं कि आप अपने खुद के readObject () -फंक्शन को परिभाषित कर सकते हैं जो पुराने डेटा को वापस पढ़ सकते हैं। यह कस्टम कोड तब serialVersionUIDपता कर सकता है कि डेटा किस संस्करण में है और यह तय करें कि इसे डी-सीरियल कैसे किया जाए। यदि आप क्रमबद्ध डेटा संग्रहीत करते हैं जो आपके कोड के कई संस्करणों से बचता है तो यह संस्करण तकनीक उपयोगी है।

लेकिन इतने लंबे समय के लिए सिलसिलेवार डेटा संग्रहीत करना बहुत आम नहीं है। एक उदाहरण के लिए अस्थायी रूप से कैश लिखने के लिए या कोडबेस के संबंधित भागों के समान संस्करण के साथ नेटवर्क को किसी अन्य प्रोग्राम में भेजने के लिए धारावाहिकीकरण तंत्र का उपयोग करना कहीं अधिक सामान्य है।

इस मामले में आप पीछे की संगतता बनाए रखने में रुचि नहीं रखते हैं। आप केवल यह सुनिश्चित करने के लिए चिंतित हैं कि कोड बेस जो संचार कर रहे हैं वास्तव में संबंधित कक्षाओं के समान संस्करण हैं। इस तरह के चेक की सुविधा के लिए, आपको serialVersionUIDपहले की तरह ही बनाए रखना चाहिए और अपनी कक्षाओं में बदलाव करते समय इसे अपडेट करना न भूलें।

यदि आप फ़ील्ड को अपडेट करना भूल जाते हैं, तो आप कक्षा के दो अलग-अलग संस्करणों को अलग-अलग संरचना के साथ समाप्त कर सकते हैं लेकिन उसी के साथ serialVersionUID। यदि ऐसा होता है, तो डिफ़ॉल्ट तंत्र ( in.defaultReadObject()) किसी भी अंतर का पता नहीं लगाएगा, और असंगत डेटा को डी-सीरियल करने का प्रयास करेगा। अब आप एक गुप्त रनटाइम त्रुटि या मूक विफलता (शून्य फ़ील्ड) के साथ समाप्त हो सकते हैं। इस प्रकार की त्रुटियां खोजना मुश्किल हो सकता है।

तो इस usecase की मदद करने के लिए, Java प्लेटफ़ॉर्म आपको serialVersionUIDमैन्युअल रूप से सेट न करने का विकल्प प्रदान करता है । इसके बजाय, क्लास संरचना का एक हैश संकलन-समय पर उत्पन्न होगा और आईडी के रूप में उपयोग किया जाएगा। यह तंत्र सुनिश्चित करेगा कि आपके पास एक ही आईडी के साथ अलग-अलग वर्ग संरचनाएं नहीं हैं, और इसलिए आपको ऊपर बताए गए इन हार्ड-टू-ट्रेस रनटाइम क्रमांकन विफलताएं नहीं मिलेंगी।

लेकिन ऑटो-जनरेटेड आईडी स्ट्रैटेजी का बैक साइड है। अर्थात् एक ही वर्ग के लिए उत्पन्न आईडी संकलक के बीच भिन्न हो सकती है (जैसा कि ऊपर जॉन स्कीट ने उल्लेख किया है)। इसलिए यदि आप विभिन्न संकलक के साथ संकलित कोड के बीच क्रमबद्ध डेटा का संचार करते हैं, तो वैसे भी मैन्युअल रूप से आईडी बनाए रखने की सिफारिश की जाती है।

और यदि आप अपने डेटा के साथ पीछे की ओर संगत हैं, जैसा कि पहले उपयोग किए गए मामले में बताया गया है, तो आप शायद खुद को आईडी बनाए रखना चाहते हैं। यह पठनीय आईडी पाने के लिए और कब और कैसे बदलते हैं इस पर अधिक नियंत्रण होता है।


4
गैर-क्षणिक क्षेत्रों को जोड़ने या हटाने से वर्ग क्रमांकन-असंगत नहीं होता है। इसलिए इस तरह के बदलावों पर 'टकराव' का कोई कारण नहीं है।
user207421

4
@ ईजेपी: हुह? डेटा जोड़ना निश्चित रूप से मेरी दुनिया में क्रमबद्धता डेटा को बदलता है।
अलेक्जेंडर टॉर्टलिंग

3
@AlexanderTorstling मैंने क्या लिखा है पढ़ें। मैंने यह नहीं कहा कि यह 'क्रमांकन डेटा को नहीं बदलता है'। मैंने कहा कि यह 'श्रेणीबद्धता-असंगत नहीं बनाता है।' यह एक ही बात नहीं है। आपको ऑब्जेक्ट सीरियलाइजेशन स्पेसिफिकेशन के वर्जनिंग चैप्टर को पढ़ने की जरूरत है।
user207421

3
@ ईजेपी: मुझे एहसास है कि एक गैर-क्षणिक क्षेत्र को जोड़ने का मतलब यह नहीं है कि आप वर्ग को क्रमबद्ध-असंगत बनाते हैं, लेकिन यह एक संरचनात्मक परिवर्तन है जो क्रमबद्ध डेटा को बदल देता है और जब तक आप ऐसा नहीं करते तब आप आमतौर पर संस्करण को टक्कर देना चाहते हैं। पश्चगामी संगतता को संभालना, जिसे मैंने बाद में पोस्ट में भी समझाया। आपकी बात बिल्कुल क्या है?
अलेक्जेंडर टॉर्टलिंग

4
मेरी बात वही है जो मैंने कही थी। गैर-क्षणिक क्षेत्रों को जोड़ना या निकालना वर्ग को असंगत नहीं बनाता है। इसलिए आपको हर बार ऐसा करने पर क्रमबद्ध रूप से अनुक्रम करने की आवश्यकता नहीं है।
user207421

72

एक सीरियलवर्सनयूआईडी क्या है और मुझे इसका उपयोग क्यों करना चाहिए?

SerialVersionUIDप्रत्येक वर्ग के लिए एक विशिष्ट पहचानकर्ता है, JVMयह सुनिश्चित करने के लिए इसका उपयोग करता है कि कक्षा के संस्करणों की तुलना यह सुनिश्चित करने के लिए की गई है कि उसी वर्ग का उपयोग Serialization के दौरान Deserialization के दौरान लोड किया गया हो।

यदि आप निर्दिष्ट नहीं करते हैं तो एक निर्दिष्ट करना अधिक नियंत्रण प्रदान करता है, हालांकि JVM एक उत्पन्न करता है। उत्पन्न मूल्य अलग-अलग संकलक के बीच भिन्न हो सकते हैं। इसके अलावा, कभी-कभी आप किसी कारण के लिए पुरानी backward incompatibilityअनुक्रमित वस्तुओं के निर्मूलन को रोकना चाहते हैं [ ], और इस मामले में आपको बस serialVersionUID को बदलना होगा।

के लिए javadocsSerializable कहते हैं :

डिफ़ॉल्ट serialVersionUID अभिकलन वर्ग विवरणों के प्रति अत्यधिक संवेदनशील है जो संकलक कार्यान्वयन के आधार पर भिन्न हो सकते हैं, और इस प्रकार डिसेरलाइज़ेशन के InvalidClassExceptionदौरान अप्रत्याशित रूप से परिणाम हो सकते हैं ।

इसलिए, आपको serialVersionUID की घोषणा करनी चाहिए क्योंकि यह हमें अधिक नियंत्रण प्रदान करता है

इस लेख में विषय पर कुछ अच्छे बिंदु हैं।


3
@Vinothbabu लेकिन serialVersionUID स्टैटिक है, इसलिए स्टैटिक वेरिएबल्स को सीरीज़ नहीं किया जा सकता है। फिर जेवीएम कैसे संस्करण की जाँच करेगा, बिना यह जाने कि वशीकरण वस्तु का संस्करण क्या है
क्रान्ति समा

3
इस उत्तर में एक बात का उल्लेख नहीं किया गया है कि आप serialVersionUIDबिना जाने क्यों सहित आँख बंद करके अनपेक्षित परिणाम पैदा कर सकते हैं । MetroidFan2002 के उत्तर पर टॉम एंडरसन की टिप्पणी से यह पता चलता है: "मैं कहूंगा कि यदि आप स्थायी भंडारण के लिए क्रमांकन का उपयोग नहीं कर रहे हैं, तो आपको मूल्य जोड़ने के बजाय @SuppressWarnings का उपयोग करना चाहिए। यह वर्ग को कम कर देता है, और यह क्षमता को संरक्षित करता है। असंगत परिवर्तन से बचाने के लिए serialVersionUID तंत्र। "
किर्बी

7
serialVersionUIDहै एक 'प्रत्येक वर्ग के लिए अद्वितीय पहचानकर्ता'। पूरी तरह से योग्य वर्ग का नाम है। यह एक संस्करण सूचक है।
user207421

58

मूल प्रश्न question यह महत्वपूर्ण क्यों है ’और where उदाहरण’ के लिए कहा है कि यह कहाँ Serial Version IDउपयोगी होगा। वैसे मुझे एक मिल गया है।

कहते हैं कि आप एक Carवर्ग बनाते हैं , इसे तुरंत बनाते हैं , और इसे एक वस्तु धारा में लिखते हैं। चपटी कार वस्तु कुछ समय के लिए फाइल सिस्टम में बैठती है। इस बीच, यदि Carएक नया क्षेत्र जोड़कर वर्ग को संशोधित किया जाता है। बाद में, जब आप चपटी हुई Carवस्तु को पढ़ने का प्रयास करते हैं (यानी डिसेर्बलाइज करते हैं) , तो आपको वह मिल जाता है (क्योंकि गणना करने की आवश्यकता नहीं होती है)। इसलिए, जैसे ही आप उन्हें नीचे दिखाए गए अनुसार बना सकते हैं, अपने सीरियल सीरियल को अपने सीरियल सीरियल में जोड़ना सबसे अच्छा अभ्यास है:java.io.InvalidClassException - क्योंकि सभी सीरियल करने योग्य वर्गों को स्वचालित रूप से एक विशिष्ट पहचानकर्ता दिया जाता है। यह अपवाद तब डाला जाता है जब वर्ग का पहचानकर्ता चपटा वस्तु के पहचानकर्ता के बराबर न हो। यदि आप वास्तव में इसके बारे में सोचते हैं, तो नए क्षेत्र को जोड़ने के कारण अपवाद को फेंक दिया जाता है। आप एक स्पष्ट serialVersionUID घोषित करके संस्करण को नियंत्रित करके फेंके जाने वाले इस अपवाद से बच सकते हैं। स्पष्ट रूप से आपके घोषित करने में एक छोटा प्रदर्शन लाभ भी हैserialVersionUID

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

और हर यूआईडी को एक रैंडम लॉन्ग नंबर देना चाहिए, न कि 1 एल।
अब्बास

4
@ अब्बास 'एक चाहिए' ऐसा क्यों? कृपया बताएं कि इससे क्या फर्क पड़ता है।
user207421

जैसा कि नाम कहता है, यह उस वर्ग के संस्करण का प्रतिनिधित्व करता है जिसका उपयोग वस्तु को क्रमबद्ध करने के लिए किया गया था। यदि आप इसे हर बार एक ही नंबर असाइन करते हैं, तो आप इसे डी-सीरियल करने के लिए सही क्लास नहीं ढूंढ पाएंगे। इसलिए जब भी आप क्लास में बदलाव करते हैं, तो संस्करण को भी बदलना बेहतर होता है।
अब्बास

2
@abbas, इस इरादे से 1और इतने पर प्राकृतिक संख्या बढ़ाने के साथ संघर्ष नहीं करता है ।
वडज़िम

2
@ BillK, मुझे लगा कि क्रमबद्धता जांच क्लासनेम और सीरियलवर्जन यूआईडी की जोड़ी से जुड़ी है। इसलिए विभिन्न वर्गों और पुस्तकालयों की विभिन्न नंबरिंग योजनाएं किसी भी तरह से हस्तक्षेप नहीं कर सकती हैं। या क्या आपने पुस्तकालयों को कोड-जनरेट किया है?
वडज़िम

42

पहले मुझे यह समझाने की आवश्यकता है कि क्रमबद्धता क्या है।

सीरियलाइज़ेशन किसी ऑब्जेक्ट को स्ट्रीम में कनवर्ट करने की अनुमति देता है, उस ऑब्जेक्ट को नेटवर्क पर भेजने या पत्र उपयोग के लिए डीबी में सहेजने या सहेजने के लिए।

क्रमबद्धता के लिए कुछ नियम हैं

  • कोई ऑब्जेक्ट केवल तभी सीरियल करने योग्य होता है जब उसका वर्ग या उसका सुपरक्लास सीरियल के इंटरफ़ेस को लागू करता है

  • एक ऑब्जेक्ट सीरियलाइज़ेबल होता है (यदि वह सुपरक्लास नहीं है, तो भी सीरियल इंटरफ़ेस को लागू करता है)। हालांकि, सीरियलस्टेबल श्रेणी के पदानुक्रम में पहला सुपरक्लास, जो कि सीरियल योग्य इंटरफ़ेस को लागू नहीं करता है, MUST में एक नो-आर्ग कंस्ट्रक्टर है। यदि इसका उल्लंघन होता है, तो readObject () एक java.io.InvalidClassException को रनटाइम में उत्पन्न करेगा

  • सभी आदिम प्रकार क्रमिक हैं।

  • क्षणिक क्षेत्र (क्षणिक संशोधक के साथ) क्रमबद्ध नहीं होते हैं, (अर्थात, सहेजे या बहाल नहीं)। एक वर्ग जो सीरियल को लागू करता है, उसे उन वर्गों के क्षणिक क्षेत्रों को चिह्नित करना चाहिए जो क्रमबद्धता का समर्थन नहीं करते हैं (उदाहरण के लिए, एक फ़ाइल स्ट्रीम)।

  • स्थैतिक क्षेत्र (स्थिर संशोधक के साथ) क्रमबद्ध नहीं हैं।

जब Objectसीरियलबद्ध किया जाता है, तो जावा रनटाइम धारावाहिक संस्करण क्रमांक उर्फ, को संबद्ध करता है serialVersionID

जहां हमें serialVersionID की आवश्यकता होती है: यह सत्यापित करने के लिए कि वाष्पीकरण के दौरान कि प्रेषक और रिसीवर क्रमबद्धता के संबंध में संगत हैं। यदि रिसीवर ने कक्षा को एक अलग से लोड किया है,serialVersionIDतो deserialization के साथ समाप्त हो जाएगाInvalidClassCastException
एक अनुक्रमिक वर्ग अपने स्वयं केserialVersionUIDस्पष्ट रूप से घोषित कर सकता है एक क्षेत्र की घोषणा की जिसका नामserialVersionUIDस्थिर, अंतिम और लंबा प्रकार होना चाहिए।

आइए एक उदाहरण के साथ यह कोशिश करें।

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();
}
}

सीरियलाइज़ ऑब्जेक्ट बनाएँ

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");
}
}

वस्तु का वर्णन करना

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());
 }
}    

नोट: अब कर्मचारी वर्ग के क्रम-निर्धारण को बदलें और सहेजें:

private static final long serialVersionUID = 4L;

और पाठक वर्ग को निष्पादित करें। लेखक वर्ग को निष्पादित करने के लिए नहीं और आपको अपवाद मिलेगा।

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)

37

यदि आपको अपनी वस्तुओं को बाइट सरणी में क्रमबद्ध करने और उन्हें भेजने / संग्रहीत करने की आवश्यकता नहीं होगी, तो आपको इसके बारे में चिंता करने की आवश्यकता नहीं है। यदि आप करते हैं, तो आपको अपने क्रमपरिवर्तन पर विचार करना चाहिए क्योंकि ऑब्जेक्ट का डीरियलाइज़र उसके क्लास लोडर के ऑब्जेक्ट के संस्करण से मेल खाएगा। जावा भाषा विनिर्देश में इसके बारे में और पढ़ें।


10
यदि आप वस्तुओं को क्रमबद्ध नहीं करने जा रहे हैं, तो वे सीरियल क्यों हैं?
इर्कसन

7
@erickson - मूल वर्ग, श्रेणीबद्ध हो सकता है, कहते हैं, ArrayList, लेकिन आप इसे आधार के रूप में उपयोग करने के लिए अपनी खुद की वस्तु (कहते हैं, एक संशोधित सरणी सूची) चाहते हैं, लेकिन आपके द्वारा बनाए गए संग्रह को क्रमबद्ध करने के लिए कभी नहीं जा रहे हैं।
MetroidFan2002

5
जावा भाषा विनिर्देश में इसका कहीं भी उल्लेख नहीं किया गया है। यह ऑब्जेक्ट संस्करण विशिष्टता में वर्णित है।
user207421

4
यहाँ जावा 8 ऑब्जेक्ट संस्करण विशिष्टता का लिंक दिया गया है ।
बेसिल बोर्के

34

यदि आपको यह चेतावनी एक ऐसे वर्ग पर मिलती है, जिसे आप कभी भी क्रमबद्ध करने के बारे में नहीं सोचते हैं, और यह कि आपने खुद को घोषित नहीं किया है implements Serializable, तो ऐसा अक्सर होता है क्योंकि आपको एक सुपरक्लास से विरासत में मिला है, जो कि सीरियल योग्य बनाता है। अक्सर तब विरासत का उपयोग करने के बजाय ऐसी वस्तु को सौंपना बेहतर होगा।

तो, के बजाय

public class MyExample extends ArrayList<String> {

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

करना

public class MyExample {
    private List<String> myList;

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

और (या ) के myList.foo()बजाय प्रासंगिक तरीकों में कॉल करें । (यह सभी मामलों में फिट नहीं है, लेकिन अभी भी काफी बार।)this.foo()super.foo()

मैं अक्सर लोगों को JFrame या इस तरह के विस्तार को देखता हूं, जब उन्हें वास्तव में केवल इसे सौंपने की आवश्यकता होती है। (यह आईडीई में ऑटो-पूर्ति के लिए भी मदद करता है, क्योंकि JFrame में सैकड़ों विधियां हैं, जिनकी आपको अपनी कक्षा में अपने कस्टम वालों को कॉल करने की आवश्यकता नहीं है।)

एक मामला जहां चेतावनी (या serialVersionUID) अपरिहार्य है, जब आप अमूर्तता से विस्तार करते हैं, आम तौर पर एक अनाम वर्ग में, केवल क्रिया-विधि जोड़कर। मुझे लगता है कि इस मामले में चेतावनी नहीं होनी चाहिए (क्योंकि आप आमतौर पर विश्वसनीय पहचान नहीं कर सकते हैं और इस तरह के गुमनाम वर्गों को वैसे भी वर्गीकृत कर सकते हैं जो आपकी कक्षा के विभिन्न संस्करणों के पार हैं), लेकिन मुझे यकीन नहीं है कि कंपाइलर इसे कैसे पहचान सकते हैं।


4
मुझे लगता है कि आप सही हैं कि अमानवीयता पर रचना अधिक समझ में आती है, खासकर जब आप एरेलेस्ट जैसे वर्गों पर चर्चा कर रहे हैं। हालाँकि, कई रूपरेखाओं में लोगों को अमूर्त सुपरक्लास से विस्तार करने की आवश्यकता होती है जो कि धारावाहिक होते हैं (जैसे कि स्ट्रट्स 1.2 के एक्शनफ़ॉर्म क्लास, या सैक्सन के एक्सटेंशनफ़ंक्शनडिफिनेशन) जिसमें यह समाधान संभव नहीं है। मुझे लगता है कि आप सही हैं, यह अच्छा होगा यदि चेतावनी को कुछ मामलों में नजरअंदाज कर दिया गया हो (जैसे कि अगर आप एक सार धारावाहिक श्रेणी से विस्तार कर रहे थे)
पीपर डे

2
निश्चित रूप से यदि आप एक वर्ग को सदस्य के रूप में जोड़ते हैं, तो उससे विरासत में मिलने के बजाय, आपको उस सदस्य वर्ग की हर विधि के लिए एक आवरण विधि लिखनी होगी, जिसका आप उपयोग करना चाहते हैं, जो कि बड़ी संख्या में स्थितियों के लिए संभव नहीं है। जब तक जावा में पर्ल के समान फ़ंक्शन __AUTOLOADनहीं है, जिसके बारे में मुझे नहीं पता है।
M_M

4
@M_M: जब आप अपनी लिपटी हुई वस्तु के लिए बहुत सारे तरीके सौंपेंगे, तो निश्चित रूप से प्रतिनिधिमंडल का उपयोग करना उचित नहीं होगा। लेकिन मुझे लगता है कि यह मामला एक डिज़ाइन गलती का संकेत है - आपकी कक्षा के उपयोगकर्ताओं (जैसे "मेनग्यू") को लिपटे ऑब्जेक्ट के कई तरीकों (जैसे JFrame) को कॉल करने की आवश्यकता नहीं होनी चाहिए।
पाओलो एबरमन

1
मुझे प्रतिनिधिमंडल के बारे में जो बात पसंद नहीं है, वह है प्रतिनिधि के लिए एक संदर्भ रखने की आवश्यकता। और हर संदर्भ का अर्थ है अधिक स्मृति। यदि मैं गलत हूं तो मुझे सही करों। अगर मुझे 100 ऑब्जेक्ट्स के एक कस्टमाइरेस्टलिस्ट की जरूरत है, तो यह ज्यादा मायने नहीं रखता है, लेकिन अगर मुझे कुछ वस्तुओं के सैकड़ों कस्टमाइजडेअर्रिस्ट्स की जरूरत है, तो मेमोरी का उपयोग काफी बढ़ जाता है।
WVrock

2
थ्रॉलेबल सीरियल करने योग्य है, और केवल थ्रोएबल ही थ्रोएबल है, इसलिए यह एक अपवाद को परिभाषित करना संभव नहीं है जो कि सीरियल करने योग्य नहीं है। प्रत्यायोजन संभव नहीं है।
फिल

22

फील्ड सीरियलवर्जन यूआईडी के महत्व को समझने के लिए, किसी को यह समझना चाहिए कि सीरियललाइज़ेशन / डिसेरिएलाइज़ेशन कैसे काम करता है।

जब एक सीरियल क्लास ऑब्जेक्ट को सीरियल किया जाता है तो जावा रनटाइम इस सीरियल किए गए ऑब्जेक्ट के साथ एक सीरियल वर्जन नंबर (जिसे सीरियलवर्सन यूआईडी कहा जाता है) को संबद्ध करता है। उस समय जब आप इस क्रमबद्ध ऑब्जेक्ट को चित्रित करते हैं, जावा रनटाइम, श्रेणी के क्रमबद्ध ऑब्जेक्ट के साथ क्रमबद्ध ऑब्जेक्ट के serialVersionUID से मेल खाता है। यदि दोनों समान हैं तो केवल आगे की प्रक्रिया के साथ आगे बढ़ता है और फिर InvalidClassException को फेंकता है।

इसलिए हम यह निष्कर्ष निकालते हैं कि सीरियललाइज़ेशन / डिसेरिएलाइज़ेशन प्रक्रिया को सफल बनाने के लिए सीरियलव्यूस्ड ऑब्जेक्ट की सीरियलव्यूडयूआईडी को क्लास के सीरियलवर्सन यूआईडी के बराबर होना चाहिए। यदि प्रोग्रामर प्रोग्राम में स्पष्ट रूप से क्रमबद्ध अनुक्रम को निर्दिष्ट करता है, तो वही मूल्य क्रमबद्ध वस्तु और वर्ग के साथ जुड़ा होगा, भले ही धारावाहिकीकरण और डीसर्लीज़ेशन प्लेटफ़ॉर्म के लिए (पूर्व के लिए) क्रमिककरण सूरज की तरह उपयोग करके खिड़कियों जैसे प्लेटफॉर्म पर किया जा सकता है। MS JVM और Deserialization Zing JVM के उपयोग से अलग-अलग प्लेटफ़ॉर्म लिनक्स पर हो सकते हैं)।

लेकिन अगर सीरियलव्यूडर यूआईडी प्रोग्रामर द्वारा निर्दिष्ट नहीं किया जाता है, तो किसी भी ऑब्जेक्ट का सीरियलाइज़ेशन \ _ डीरियलाइज़ेशन करते समय, जावा रनटाइम इसकी गणना करने के लिए अपने एल्गोरिथ्म का उपयोग करता है। यह serialVersionUID गणना एल्गोरिथ्म एक JRE से दूसरे में भिन्न होता है। यह भी संभव है कि जिस वातावरण में ऑब्जेक्ट को क्रमबद्ध किया जाता है वह एक JRE (उदा: SUN JVM) का उपयोग कर रहा है और वह वातावरण जहाँ deserialzation होता है, Linux Jvm (zing) का उपयोग कर रहा है। ऐसे मामलों में क्रमबद्ध ऑब्जेक्ट से जुड़े serialVersionUID, deserialzid वातावरण में गणना की गई श्रेणी के serialVersionUID से भिन्न होंगे। बदले में डिसेरिएलाइजेशन सफल नहीं होगा। तो ऐसी स्थितियों / मुद्दों से बचने के लिए प्रोग्रामर को क्रमिक श्रेणी के क्रमबद्ध धारावाहिक को हमेशा निर्दिष्ट करना चाहिए।


2
एल्गोरिथ्म में भिन्नता नहीं है, लेकिन यह थोड़ा अंडर-निर्दिष्ट है।
user207421

... एल्गोरिथ्म में भिन्नता नहीं है, लेकिन यह थोड़ा कम-निर्दिष्ट है ... जिसका अर्थ है कि कोई भी jvm भिन्न हो सकता है ..... @ user207421
AnthonyJClink

18

परेशान न हों, डिफ़ॉल्ट गणना वास्तव में अच्छी है और 99,9999% मामलों के लिए पर्याप्त है। और यदि आप समस्याओं में भाग लेते हैं, तो आप कर सकते हैं - जैसा कि पहले ही कहा गया है - यूआईडी को परिचय की जरूरत के रूप में प्रस्तुत करें (जो कि अत्यधिक संभावना नहीं है)


2
बकवास। यह उस मामले में पर्याप्त है जहां कक्षा नहीं बदली गई है। आपके पास '99 .9999% 'का समर्थन करने के लिए शून्य प्रमाण हैं।
user207421

18

उदाहरण के लिए जहां लापता सीरियलवर्जन यूआईडी के कारण समस्या हो सकती है:

मैं इस जावा ईई एप्लिकेशन पर काम कर रहा हूं जो एक वेब मॉड्यूल से बना है जो एक मॉड्यूल का उपयोग करता है EJB। वेब मॉड्यूल EJBमॉड्यूल को दूरस्थ रूप से कॉल करता है और तर्क के रूप में POJOउस उपकरण Serializableको लागू करता है।

इस POJO'sक्लास को EJB जार के अंदर पैक किया गया था और इसके अंदर वेब मॉड्यूल के WEB-INF / lib में जार है। वे वास्तव में एक ही वर्ग हैं, लेकिन जब मैं EJB मॉड्यूल को पैकेज करता हूं तो मैं इस POJO के जार को EJB मॉड्यूल के साथ एक साथ पैक करने के लिए अनपैक करता हूं।

EJBनीचे दिया गया अपवाद के साथ कॉल विफल हो रहा था क्योंकि मैंने इसकी घोषणा नहीं की थी serialVersionUID:

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

16

मैं आमतौर पर serialVersionUIDएक संदर्भ में उपयोग करता हूं : जब मुझे पता है कि यह जावा वीएम के संदर्भ को छोड़ देगा।

मुझे यह तब पता चलेगा जब मैं उपयोग करना चाहता हूं ObjectInputStreamऔर ObjectOutputStreamअपने आवेदन के लिए या यदि मुझे कोई पुस्तकालय / रूपरेखा पता है तो मैं इसका उपयोग करूंगा। SerialVersionID यह सुनिश्चित करता है कि अलग-अलग संस्करणों या विक्रेताओं के विभिन्न जावा वीएम सही ढंग से संचालित होंगे या यदि इसे वीएम के बाहर संग्रहीत और पुनर्प्राप्त किया जाता है उदाहरण के HttpSessionलिए सत्र डेटा एप्लिकेशन सर्वर के पुनरारंभ और उन्नयन के दौरान भी रह सकता है।

अन्य सभी मामलों के लिए, मैं उपयोग करता हूं

@SuppressWarnings("serial")

चूंकि अधिकांश समय डिफ़ॉल्ट serialVersionUIDपर्याप्त होता है। इसमें शामिल हैं Exception, HttpServlet


इसमें कंटेनरों में HttpServlet शामिल नहीं है, जहां उन्हें स्वैप किया जा सकता है, या उदाहरण के लिए RMI में अपवाद।
user207421

14

फ़ील्ड डेटा कक्षा में संग्रहीत कुछ सूचनाओं का प्रतिनिधित्व करता है। क्लास Serializableइंटरफ़ेस को लागू करता है, इसलिए ग्रहण स्वचालित रूप से serialVersionUIDक्षेत्र को घोषित करने की पेशकश करता है । मान 1 सेट से शुरू होता है।

यदि आप नहीं चाहते कि चेतावनी आए, तो इसका उपयोग करें:

@SuppressWarnings("serial")

11

यह अच्छा होगा यदि CheckStyle यह सत्यापित कर सके कि Serializable नामक एक वर्ग पर serialVersionUID लागू होता है, जिसका अर्थ है कि यह धारावाहिक संस्करण आईडी जनरेटर से क्या मेल खाता है। यदि आपके पास बहुत सारे सीरियल करने योग्य डीटीओ के साथ एक परियोजना है, उदाहरण के लिए, मौजूदा serialVersionUID को हटाने के लिए याद रखना और इसे पुन: उत्पन्न करना एक दर्द है, और वर्तमान में यह सत्यापित करने का एकमात्र तरीका (कि मुझे पता है) प्रत्येक वर्ग के लिए पुन: उत्पन्न करना और तुलना करना है पुराना वाला। यह बहुत दर्दनाक है।


8
यदि आप सीरियलव्यूड यूआईडी को हमेशा उसी मूल्य पर सेट करते हैं जो जनरेटर उत्पन्न करेगा, तो आपको वास्तव में इसकी आवश्यकता नहीं है। सब के बाद, इसके raison d'être परिवर्तनों के बाद एक ही रहना है, जब वर्ग अभी भी संगत है।
पाओलो एबरमन

4
कारण यह है कि विभिन्न संकलक एक ही वर्ग के लिए समान मूल्य के साथ आते हैं। के रूप में javadocs में समझाया (ऊपर भी उत्तर दिया गया है), उत्पन्न संस्करण भंगुर है और तब भी भिन्न हो सकता है जब वर्ग ठीक से उपयुक्त न हो। जब तक आप प्रत्येक बार एक ही कंपाइलर पर यह परीक्षण चलाते हैं, तब तक यह सुरक्षित होना चाहिए। अगर आप jdk को अपग्रेड करते हैं तो भगवान आपकी मदद करते हैं और एक नया नियम सामने आता है, भले ही आपने कोड नहीं बदला हो।
एंड्रयू बैकर

2
यह मिलान करने के लिए आवश्यक नहीं है कि क्या serialverउत्पादन होगा। -1
user207421

सामान्य तौर पर यह बिल्कुल आवश्यक नहीं है। @ एंड्रयूबॅकर के मामले में .java फाइल पर एक ही तरह के दो अलग-अलग कंपाइलर की आवश्यकता होती है। .class फाइलों के दोनों संस्करणों में एक-दूसरे के साथ संचार होता है - अधिकांश समय जब आप क्लास बनाते हैं और इसे वितरित करते हैं। अगर ऐसा है, तो एसयूआईडी नहीं होने से ठीक काम होगा।
बिल K

1
स्टोरेज / रिट्रीवल के प्रयोजनों के लिए सही मायने में सीरियलाइजेशन का उपयोग करने वाले लोग आम तौर पर serialVersionUID1 पर सेट होंगे । यदि कक्षा का एक नया संस्करण असंगत है, लेकिन फिर भी पुराने डेटा को संभालने में सक्षम होने की आवश्यकता है, तो आप संस्करण संख्या में वृद्धि करते हैं और विशेष कोड जोड़ते हैं पुराने प्रारूपों से निपटें। मैं हर बार रोता हूं जब मैं serialVersionUID1 अंक से बड़ा देखता हूं , या तो क्योंकि यह एक यादृच्छिक संख्या (बेकार) था या क्योंकि कक्षा को स्पष्ट रूप से 10 से अधिक विभिन्न संस्करणों से निपटने की आवश्यकता होती है।
जॉन 16384

11

SerialVersionUID का उपयोग ऑब्जेक्ट के संस्करण नियंत्रण के लिए किया जाता है। आप अपने वर्ग फ़ाइल में serialVersionUID को भी निर्दिष्ट कर सकते हैं। SerialVersionUID को निर्दिष्ट नहीं करने का परिणाम यह है कि जब आप कक्षा में किसी भी फ़ील्ड को जोड़ते या संशोधित करते हैं तो पहले से ही क्रमबद्ध वर्ग पुनर्प्राप्त नहीं कर पाएगा क्योंकि नए वर्ग के लिए और पुराने क्रमबद्ध ऑब्जेक्ट के लिए उत्पन्न serialVersionUID भिन्न होगा। जावा सीरियलाइज़ेशन प्रक्रिया क्रमबद्ध ऑब्जेक्ट की स्थिति को ठीक करने के लिए सही serialVersionUID पर निर्भर करती है और java.io.InvalidClassException को सीरियलवर्सन यूआईडी बेमेल के मामले में फेंक देती है।

और पढ़ें: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ


9

जावा में कक्षा के SerialVersionUIDअंदर का उपयोग क्यों करें Serializable?

serializationजावा रनटाइम के दौरान , एक वर्ग के लिए एक संस्करण संख्या बनाता है, ताकि बाद में इसे डी-सीरियल कर सके। इस संस्करण संख्या को SerialVersionUIDजावा में कहा जाता है।

SerialVersionUIDक्रमबद्ध डेटा का उपयोग करने के लिए किया जाता है। यदि आप SerialVersionUIDअनुक्रमित उदाहरण से मेल खाते हैं, तो आप केवल एक वर्ग को डी-सीरियल कर सकते हैं । जब हम SerialVersionUIDअपनी कक्षा में घोषित नहीं करते हैं , तो जावा रनटाइम हमारे लिए इसे बनाता है लेकिन इसकी अनुशंसा नहीं की जाती है। डिफ़ॉल्ट तंत्र से बचने के लिए SerialVersionUIDइसे private static final longचर घोषित करने की अनुशंसा की जाती है ।

जब आप Serializableमार्कर इंटरफ़ेस को लागू करने के रूप में एक वर्ग की घोषणा करते हैं java.io.Serializable, तो जावा रनटाइम डिफ़ॉल्ट सीरियलाइज़ेशन तंत्र का उपयोग करके उस वर्ग के डिस्क में बनी रहती है, बशर्ते आपने Externalizableइंटरफ़ेस का उपयोग करके प्रक्रिया को अनुकूलित नहीं किया हो ।

यह भी देखें कि जावा में Serializable वर्ग के अंदर SerialVersionUID का उपयोग क्यों करें

कोड: javassist.SerialVersionUID


8

यदि आप बड़ी संख्या में ऐसी कक्षाओं में संशोधन करना चाहते हैं, जिनमें पुरानी कक्षाओं के साथ संगतता बनाए रखते हुए पहली बार में कोई सीरियलवीडरयूआईडी सेट नहीं किया गया था, तो इंटेलीज आइडिया, एक्लिप्स जैसे उपकरण कम हो जाते हैं क्योंकि वे यादृच्छिक संख्या उत्पन्न करते हैं और फाइलों के एक गुच्छा पर काम नहीं करते हैं। एक बार में। मैं निम्नलिखित बैश स्क्रिप्ट पर आता हूं (मुझे विंडोज़ उपयोगकर्ताओं के लिए खेद है, एक मैक खरीदने पर विचार करें या लिनक्स में बदलें) धारावाहिक को संशोधित करना आसान बनाने के लिए समस्या का हल करें:

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

आप इस लिपि को सहेजते हैं, add_serialVersionUID.sh को आप ~ / bin कहते हैं। फिर आप इसे अपने मावेन या ग्रैडल प्रोजेक्ट की रूट डायरेक्टरी में चलाते हैं जैसे:

add_serialVersionUID.sh < myJavaToAmend.lst

इस .lst में शामिल है जावा फाइल की सूची में निम्नलिखित प्रारूप में क्रमबद्ध धारावाहिक जोड़ने के लिए:

com/abc/ic/api/model/domain/item/BizOrderTransDO.java
com/abc/ic/api/model/domain/item/CardPassFeature.java
com/abc/ic/api/model/domain/item/CategoryFeature.java
com/abc/ic/api/model/domain/item/GoodsFeature.java
com/abc/ic/api/model/domain/item/ItemFeature.java
com/abc/ic/api/model/domain/item/ItemPicUrls.java
com/abc/ic/api/model/domain/item/ItemSkuDO.java
com/abc/ic/api/model/domain/serve/ServeCategoryFeature.java
com/abc/ic/api/model/domain/serve/ServeFeature.java
com/abc/ic/api/model/param/depot/DepotItemDTO.java
com/abc/ic/api/model/param/depot/DepotItemQueryDTO.java
com/abc/ic/api/model/param/depot/InDepotDTO.java
com/abc/ic/api/model/param/depot/OutDepotDTO.java

यह स्क्रिप्ट हुड के नीचे JDK serialVer टूल का उपयोग करती है। इसलिए सुनिश्चित करें कि आपका $ JAVA_HOME / बिन पथ में है।


2
मुझे एक विचार देता है: हमेशा सीरियल संस्करण को इस तरह से एक उपकरण के साथ पुनर्जीवित करें, कभी भी हाथ से नहीं, रिलीज करने से पहले - इस तरह, आप एक वर्ग में बदलाव करने से बचते हैं जिसका सीरियल संस्करण uid एक वास्तविक के कारण बदल जाना चाहिए था असंगत परिवर्तन। मैन्युअल रूप से उस पर नज़र रखना बहुत कठिन है।
इग्नाजियो

6

यह सवाल जोशुआ बलोच द्वारा प्रभावी जावा में बहुत अच्छी तरह से प्रलेखित है। एक बहुत अच्छी किताब और एक पढ़ी जानी चाहिए। मैं नीचे दिए गए कारणों में से कुछ को रेखांकित करूंगा:

क्रमांकन रनटाइम प्रत्येक क्रमिक वर्ग के लिए सीरियल संस्करण नामक एक संख्या के साथ आता है। इस संख्या को सीरियलवर्सन यूआईडी कहा जाता है। अब इस संख्या के पीछे कुछ गणित है और यह उन क्षेत्रों / विधियों के आधार पर सामने आता है जिन्हें कक्षा में परिभाषित किया गया है। एक ही वर्ग के लिए हर बार एक ही संस्करण उत्पन्न होता है। इस संख्या का उपयोग deserialization के दौरान यह सत्यापित करने के लिए किया जाता है कि किसी सीरीज़ ऑब्जेक्ट के प्रेषक और रिसीवर ने उस ऑब्जेक्ट के लिए कक्षाएं लोड की हैं जो क्रमांकन के संबंध में संगत हैं। यदि रिसीवर ने ऑब्जेक्ट के लिए एक वर्ग लोड किया है, जिसमें संबंधित प्रेषक वर्ग की तुलना में एक अलग सीरियलवर्जन यूआईडी है, तो डिसेरिअलाइज़ेशन का परिणाम एक InvalidClassException के रूप में होगा।

यदि वर्ग क्रमबद्ध है, तो आप अपने स्वयं के सीरियलव्यूडयूआईडी को स्पष्ट रूप से "सीरियलव्यूडयूआईडी" नामक एक क्षेत्र घोषित करके भी घोषित कर सकते हैं जो कि स्थिर, अंतिम और लंबे प्रकार का होना चाहिए। अधिकांश IDE जैसे कि ग्रहण आपको उस लंबे स्ट्रिंग को उत्पन्न करने में मदद करता है।


6

हर बार जब किसी ऑब्जेक्ट को क्रमबद्ध किया जाता है तो ऑब्जेक्ट को ऑब्जेक्ट की क्लास के लिए एक वर्जन आईडी नंबर के साथ स्टैम्प किया जाता है। इस आईडी को serialVersionUID कहा जाता है और यह क्लास स्ट्रक्चर के बारे में जानकारी के आधार पर गणना की जाती है। मान लीजिए कि आपने एक कर्मचारी वर्ग बनाया है और इसका संस्करण आईडी # 333 (जेवीएम द्वारा सौंपा गया है) है, अब जब आप उस वर्ग की वस्तु को क्रमबद्ध करेंगे (मान लीजिए कर्मचारी वस्तु), तो जेवीएम इसे 333 के रूप में यूआईडी असाइन करेगा।

एक स्थिति पर विचार करें - भविष्य में आपको अपनी कक्षा को संपादित करने या बदलने की आवश्यकता है और उस स्थिति में जब आप इसे संशोधित करते हैं, तो जेवीएम इसे एक नया यूआईडी (मान लीजिए # 444) असाइन करेगा। अब जब आप कर्मचारी ऑब्जेक्ट को डिसेर्बलाइज करने की कोशिश करते हैं, तो JVM सीरियल की ऑब्जेक्ट (एम्प्लॉई ऑब्जेक्ट) वर्जन ID (# 333) की तुलना उस क्लास (# 444) (जब से इसे बदला गया था) से करेगा। तुलना करने पर JVM दोनों संस्करण UID अलग-अलग होंगे और इसलिए Deserialization विफल हो जाएगा। इसलिए यदि हर वर्ग के लिए serialVersionID प्रोग्रामर द्वारा ही परिभाषित किया जाता है। यह भविष्य में भी विकसित होने पर भी वैसा ही होगा और इसलिए जेवीएम हमेशा यह पाएगा कि वर्ग बदले हुए होते हुए भी श्रेणीबद्ध वस्तु के अनुकूल है। अधिक जानकारी के लिए आप HEAD FIRST JAVA के अध्याय 14 का उल्लेख कर सकते हैं।


1
हर बार किसी वस्तु के वर्ग को क्रमबद्ध किया serialVersionUIDजाता है। यह हर वस्तु के साथ नहीं भेजा जाता है।
user207421

3

एक सरल स्पष्टीकरण:

  1. क्या आप डेटा अनुक्रमित कर रहे हैं?

    सीरियललाइज़ेशन मूल रूप से एक फ़ाइल / स्ट्रीम / आदि के लिए क्लास डेटा लिख ​​रहा है। De-serialization उस डेटा को एक कक्षा में वापस पढ़ रहा है।

  2. क्या आप उत्पादन में जाने का इरादा रखते हैं?

    यदि आप महत्वहीन / नकली डेटा के साथ कुछ परीक्षण कर रहे हैं, तो इसके बारे में चिंता न करें (जब तक कि आप सीधे क्रमांकन परीक्षण नहीं कर रहे हैं)।

  3. क्या यह पहला संस्करण है?

    यदि हां, सेट करें serialVersionUID=1L

  4. यह दूसरा, तीसरा, आदि ठेस संस्करण है?

    अब आपको इसके बारे में चिंता करने की ज़रूरत है serialVersionUID, और इसे गहराई से देखना चाहिए।

मूल रूप से, यदि आप उस वर्जन को सही ढंग से अपडेट नहीं करते हैं, जब आप एक वर्ग को अपडेट करते हैं, जिसे आपको लिखने / पढ़ने की आवश्यकता होती है, तो पुराने डेटा को पढ़ने की कोशिश करने पर आपको एक त्रुटि मिलेगी।


2

'serialVersionUID ’एक 64 बिट संख्या है जिसका उपयोग विलगति प्रक्रिया के दौरान विशिष्ट रूप से एक वर्ग की पहचान करने के लिए किया जाता है। जब आप किसी ऑब्जेक्ट को क्रमबद्ध करते हैं, तो क्लास के सीरियलवर्सनयूआईडी को भी फाइल में लिखा जाता है। जब भी आप इस ऑब्जेक्ट को डिस्क्राइब करते हैं, तो java run time इस serialVersionUID मान को क्रमबद्ध डेटा से निकालता है और क्लास के साथ समान वैल्यू एसोसिएट की तुलना करता है। यदि दोनों मेल नहीं खाते हैं, तो 'java.io.InvalidClassException' को फेंक दिया जाएगा।

यदि कोई सीरियल करने योग्य वर्ग स्पष्ट रूप से एक सीरियलव्यूडयूआईडी घोषित नहीं करता है, तो क्रमांकन रनटाइम उस वर्ग के लिए सीरियलवर्सन यूआईडी मूल्य की गणना करेगा, जैसे कि फ़ील्ड, विधियों आदि जैसे वर्ग के विभिन्न पहलुओं के आधार पर। आप डेमो एप्लिकेशन के लिए इस लिंक को संदर्भित कर सकते हैं ।


1

लंबी कहानी को छोटा बताने के लिए इस क्षेत्र का उपयोग यह जांचने के लिए किया जाता है कि क्या धारावाहिक डेटा को सही ढंग से डिसेरलाइज़ किया जा सकता है। सीरियलाइज़ेशन और डिसेरिएलाइज़ेशन अक्सर कार्यक्रम की विभिन्न प्रतियों द्वारा किए जाते हैं - उदाहरण के लिए सर्वर स्ट्रिंग को ऑब्जेक्ट में कनवर्ट करता है और क्लाइंट को स्ट्रिंग को ऑब्जेक्ट में कनवर्ट करता है। यह क्षेत्र बताता है कि दोनों एक ही विचार के साथ काम करते हैं कि यह वस्तु क्या है। जब यह फ़ील्ड मदद करती है:

  • आपके पास विभिन्न स्थानों (जैसे 1 सर्वर और 100 ग्राहक) में आपके कार्यक्रम की कई अलग-अलग प्रतियां हैं। यदि आप अपनी वस्तु बदलेंगे, अपना संस्करण क्रमांक बदलेंगे और इस क्लाइंट को अपडेट करना भूल जाएंगे, तो यह पता चलेगा कि वह डिसेरिएशन के लिए सक्षम नहीं है

  • आपने अपना डेटा किसी फ़ाइल में संग्रहीत किया है और बाद में आप इसे संशोधित ऑब्जेक्ट के साथ अपने प्रोग्राम के अद्यतन संस्करण के साथ खोलने का प्रयास करते हैं - आपको पता चल जाएगा कि यदि आप अपना संस्करण सही रखते हैं तो यह फ़ाइल संगत नहीं है

यह कब महत्वपूर्ण है?

सबसे स्पष्ट - यदि आप अपनी फ़ील्ड में कुछ फ़ील्ड जोड़ते हैं, तो पुराने संस्करण उनका उपयोग करने में सक्षम नहीं होंगे, क्योंकि उनके पास ये फ़ील्ड उनके ऑब्जेक्ट संरचना में नहीं हैं।

कम स्पष्ट - जब आप ऑब्जेक्ट को डिस्क्राइबलाइज करते हैं, तो फ़ील्ड्स जहां स्ट्रिंग में मौजूद नहीं हैं उन्हें NULL के रूप में रखा जाएगा। यदि आपने अपनी ऑब्जेक्ट से फ़ील्ड निकाल दी है, तो पुराने संस्करण इस फ़ील्ड को allways-NULL के रूप में रखेंगे, जिससे दुर्व्यवहार हो सकता है यदि पुराने संस्करण इस फ़ील्ड में डेटा पर भरोसा करते हैं (वैसे भी आपने इसे किसी चीज़ के लिए बनाया है, न कि केवल मज़े के लिए :-))

कम से कम स्पष्ट - कभी-कभी आप उस विचार को बदलते हैं जो आप किसी क्षेत्र के अर्थ में रखते हैं। उदाहरण के लिए जब आप 12 वर्ष के होते हैं, तो आप "बाइक" के तहत "साइकिल" से मतलब रखते हैं, लेकिन जब आप 18 वर्ष के होते हैं, तो आपका मतलब "मोटरसाइकिल" होता है - यदि आपके दोस्त आपको "शहर भर में बाइक की सवारी" के लिए आमंत्रित करेंगे और आप केवल वही होंगे, जो साइकिल पर आए, आप यह जानेंगे कि खेतों में समान अर्थ रखना कितना महत्वपूर्ण है :-)


1

सबसे पहले आपके प्रश्न का उत्तर देने के लिए, जब हम अपनी कक्षा में SerialVersionUID की घोषणा नहीं करते हैं, तो जावा रनटाइम हमारे लिए इसे उत्पन्न करता है, लेकिन यह प्रक्रिया कई वर्ग मेटा डेटा के प्रति संवेदनशील है जिसमें फ़ील्ड्स की संख्या, फ़ील्ड्स का प्रकार, फ़ील्ड्स का एक्सेस संशोधक, इंटरफ़ेस लागू किया गया है वर्ग आदि द्वारा इसलिए इसे स्वयं घोषित करने की अनुशंसा की जाती है और ग्रहण आपको उसी के बारे में चेतावनी दे रहा है।

सीरियलाइज़ेशन: हम अक्सर उन महत्वपूर्ण वस्तुओं के साथ काम करते हैं जिनकी स्थिति (ऑब्जेक्ट के वेरिएबल्स में डेटा) इतनी महत्वपूर्ण है कि हम ऑब्जेक्ट / स्टेट को भेजने के मामले में पावर / सिस्टम विफलताओं (या) नेटवर्क विफलताओं के कारण इसे खोने का जोखिम नहीं उठा सकते हैं। मशीन। इस समस्या के समाधान को "दृढ़ता" नाम दिया गया है, जिसका अर्थ है कि डेटा को बनाए रखना (सहेजना / सहेजना)। निरंतरता कई अन्य तरीकों में से एक है दृढ़ता को प्राप्त करने के लिए (डेटा को डिस्क / मेमोरी में सहेजकर)। ऑब्जेक्ट की स्थिति को सहेजते समय, ऑब्जेक्ट के लिए एक पहचान बनाना महत्वपूर्ण है, इसे ठीक से वापस पढ़ने में सक्षम होने के लिए (डे-सीरियल)। यह विशिष्ट पहचान है ID SerialVersionUID।


0

SerialVersionUID क्या है? उत्तर: - कहते हैं कि दो व्यक्ति हैं, एक मुख्यालय से और दूसरा ODC से, दोनों क्रमशः क्रमबद्धता और विलुप्ति का प्रदर्शन करने जा रहे हैं। इस मामले में यह प्रमाणित करने के लिए कि रिसीवर ODC में है, प्रमाणित व्यक्ति है, JVM एक विशिष्ट आईडी बनाता है जिसे SerialVersionUID के रूप में जाना जाता है।

यहाँ परिदृश्य पर आधारित एक अच्छी व्याख्या है,

क्यों SerialVersionUID?

सीरियलाइजेशन : क्रमबद्धता के समय, हर ऑब्जेक्ट प्रेषक पक्ष के साथ JVM एक विशिष्ट पहचानकर्ता को बचाएगा। JVM संबंधित .class फ़ाइल के आधार पर उस विशिष्ट ID को जनरेट करने के लिए जिम्मेदार है जो प्रेषक प्रणाली में मौजूद है।

deserialization : के समय, रिसीवर साइड JVM ऑब्जेक्ट के साथ जुड़े यूनिक आईडी की तुलना लोकल क्लास यूनिक आईडी से करेगा। JVM संबंधित .class फाइल के आधार पर एक यूनिक आईडी भी बनाएगा जो रिसीवर सिस्टम में मौजूद है। यदि दोनों यूनिक आईडी मेल खाते हैं तो केवल डीरिएरलाइजेशन का प्रदर्शन किया जाएगा। अन्यथा हम InvalidClassException कहते हुए रनटाइम अपवाद प्राप्त करेंगे। यह विशिष्ट पहचानकर्ता कुछ और नहीं बल्कि SerialVersionUID है

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.