क्यों एक साधारण 1L के बजाय लंबे serialVersionUID उत्पन्न करते हैं?


210

जब कक्षा ग्रहण में सीरियल लागू करता है, मेरे पास दो विकल्प हैं: डिफ़ॉल्ट जोड़ें serialVersionUID(1L)या उत्पन्न करें serialVersionUID(3567653491060394677L)। मुझे लगता है कि पहले एक कूलर है, लेकिन कई बार मैंने लोगों को दूसरे विकल्प का उपयोग करते हुए देखा। उत्पन्न करने का कोई कारण है long serialVersionUID?


49
वह सटीक नकल कैसे है? मैं यह नहीं पूछता कि यह सब क्यों उत्पन्न होता है, लेकिन क्यों लंबे सीरियलव्यूड यूआईडी उत्पन्न करते हैं।
एडेप्टर

13
जब जॉन स्कीट serialVersionUID का उपयोग करता है, तो वह 0L: stackoverflow.com/questions/605828/… ;) का उपयोग करता है
हन्नो फिएट

8
@ हनोफिएट: सटीक वाक्य है: "सादगी के लिए मैं 0 से शुरू करने और इसे 1 के साथ बढ़ाने की सलाह दूंगा जो आपको चाहिए।" इसलिए, ऐसा लगता है कि वह 0Lकेवल शुरुआत में उपयोग करता है ।
या

7
@ORMapper: क्या आप यह बता रहे हैं कि जॉन स्कीट को अपने लिखे गए कोड को वापस लेने और अपडेट करने की आवश्यकता है? यहां तक ​​कि संरचनात्मक असंगति के बिंदु तक। दम तोड़ देना! विधर्म!
थिलो

जवाबों:


90

जहां तक ​​मैं बता सकता हूं, यह केवल पिछले रिलीज के साथ संगतता के लिए होगा। यह केवल तभी उपयोगी होगा जब आपने पहले सीरियलवर्ट यूआईडी का उपयोग करने की उपेक्षा की हो, और फिर एक ऐसा बदलाव किया जिसे आप जानते हैं कि यह संगत होना चाहिए लेकिन इससे सीरियलाइजेशन टूट जाता है।

देखें जावा क्रमबद्धता युक्ति अधिक जानकारी के लिए।


69

क्रमबद्धकरण संस्करण UID का उद्देश्य वस्तुओं के वैध क्रमांकन करने के लिए एक वर्ग के विभिन्न संस्करणों पर नज़र रखना है।

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

हमेशा एक ही आईडी का उपयोग करना, जैसे 1Lकि भविष्य में, यदि वर्ग परिभाषा को बदल दिया जाता है जो क्रमबद्ध ऑब्जेक्ट की संरचना में परिवर्तन का कारण बनता है, तो एक अच्छा मौका होगा कि किसी ऑब्जेक्ट को डिसेर्बलाइज करने की कोशिश करते समय समस्याएं उत्पन्न होती हैं।

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

यहाँ उन लेखों के लिंक दिए गए हैं जो क्रमबद्धता और कक्षाओं के संस्करण पर चर्चा करते हैं:


50
1L का उपयोग करने के पीछे का विचार यह है कि आप हर बार जब आप वर्ग के गुणों या विधियों को बदलते हैं तो इसे बढ़ाते हैं।
पॉवरलॉर्ड

39
क्रमिक प्रदर्शन को स्वचालित रूप से उत्पन्न करने की अनुमति देने का कोई रनटाइम प्रदर्शन प्रभाव नहीं है - यह javac द्वारा संकलित समय पर उत्पन्न होता है ... यदि आप वर्ग के बाइटकोड को विघटित करते हैं, तो आप वास्तव में चर को बाइटकोड में देखेंगे।
जारेड

11
एक और ध्यान दें - स्पष्ट रूप से संख्या का प्रबंधन करके आप यह तय करते हैं कि आप वर्ग "संगत" के संस्करणों पर विचार करते हैं, बजाय कक्षा की परिभाषा को बिल्कुल समान करने की आवश्यकता के।
स्कॉट स्टैनफील्ड

23
जोश बलोच के प्रभावी जावा: 2 संस्करण में आइटम 75 के अनुसार @ जारेड: "आपके द्वारा लिखे जाने वाले प्रत्येक धारावाहिक श्रेणी में एक स्पष्ट धारावाहिक संस्करण यूआईडी घोषित करें .... यदि कोई सीरियल संस्करण यूआईडी प्रदान नहीं किया गया है, तो रनटाइम पर एक उत्पन्न करने के लिए एक महंगी गणना की आवश्यकता होती है। । "
कॉलिन के

12
@coobird यह मुख्य कारण लगता है कि डिफ़ॉल्ट serialVersionUID की अनुशंसा नहीं की गई है Note - It is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected serialVersionUID conflicts during deserialization, causing deserialization to fail. । उपरोक्त टिप्पणी जावा वस्तु क्रमांकन विशिष्टता संस्करण 6.0 से ली गई है
user624558

20

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


1
ठीक है, लेकिन वही होगा यदि मेरे पास हमेशा 1 एल है। अगर मैं कोई बदलाव करूंगा तो भी सब कुछ संगत होगा।
grep

@grep एक फ़ील्ड का नाम बदलने का प्रयास करें और फिर देखें कि क्या होता है।
तर्जका

1
@grep बिंदु यह है कि यदि आपके पास एक वर्ग है जो पहले serialVersionUID को छोड़ दिया है, तो यह स्वचालित रूप से उत्पन्न होगा। तो अब, आप इसे स्पष्ट रूप से सेट करना शुरू करना चाहते हैं, इसे 1L पर सेट करना मौजूदा वर्ग के लिए असंगत बना देगा, जबकि उत्पन्न मूल्य का उपयोग करना इसे संगत रखता है।
marc82ch

15

के "लंबे" डिफ़ॉल्ट serialVersionUIDजावा क्रमांकन विनिर्देश द्वारा परिभाषित डिफ़ॉल्ट धारावाहिक व्यवहार से गणना की जाती है।

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

यदि आपको मौजूदा बिट धाराओं के अनुकूल नहीं होना है, तो आप बस 1Lवहां डाल सकते हैं और कुछ परिवर्तन होने पर आवश्यकतानुसार संस्करण बढ़ा सकते हैं। अर्थात्, जब परिवर्तित वर्ग का डिफ़ॉल्ट क्रमांकन संस्करण पुराने वर्ग के डिफ़ॉल्ट संस्करण से भिन्न होगा।


11

हर बार जब आप एक वर्ग को परिभाषित करते हैं, जो लागू करता है, तो आपको पूरी तरह से एक सीरियलव्यूड बनाना चाहिए java.io.Serializable। यदि आप नहीं करते हैं, तो आपके लिए एक स्वचालित रूप से बनाया जाएगा, लेकिन यह बुरा है। ऑटो-जनरेटेड सीरियलवर्जन यूआईडी आपकी कक्षा के विधि हस्ताक्षरों पर आधारित है, इसलिए यदि आप भविष्य में अपनी कक्षा को एक विधि में जोड़ने के लिए बदलते हैं (उदाहरण के लिए), तो कक्षा के "पुराने" संस्करणों को असफल कर दिया जाएगा। यहाँ क्या हो सकता है:

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

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

6

यदि आप एक serialVersionUID निर्दिष्ट नहीं करते हैं, तो जावा मक्खी पर एक बनाता है। उत्पन्न क्रमांक VVUUID वह संख्या है। यदि आप अपनी कक्षा में कुछ ऐसा परिवर्तन करते हैं जो वास्तव में आपकी कक्षा को पिछली क्रमबद्ध क्रिया-कलापों से असंगत नहीं बनाता है, लेकिन हैश को बदल देता है, तो आपको जनरेट किए गए बहुत-बड़े-बड़े सीरियलवर्जन यूआईडी (या त्रुटि संदेश से "अपेक्षित" संख्या) का उपयोग करने की आवश्यकता है । अन्यथा, यदि आप सब कुछ का ट्रैक रख रहे हैं, तो 0, 1, 2 ... बेहतर है।


आप का मतलब ==> 1. यदि आप चाहते हैं कि वर्गों के विभिन्न परिवर्तन संगत होने के लिए तैयार हों। 2. यदि आप चाहते हैं कि वर्गों के विभिन्न संस्करण असंगत उपयोग के लिए डिफ़ॉल्ट हों, और वेतन वृद्धि में विवेकपूर्ण हों। क्या मैंने इसे सही तरीके से समझा?
20

4

जब आप serialVersionUID (35L653491060394677L) का निर्माण करने के बजाय serialVersionUID (1L) का उपयोग करते हैं तो आप कुछ कह रहे हैं।

आप कह रहे हैं कि आप 100% आश्वस्त हैं कि कोई भी प्रणाली इस वर्ग को कभी नहीं छूएगी जिसके पास इस श्रेणी का असंगत अनुक्रमित संस्करण है जिसका संस्करण संख्या 1 है।

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

तुम उस पर तड़प सकते हो। या आप हारने की उम्मीद कर लॉटरी खेल सकते हैं। यदि आप संस्करण उत्पन्न करते हैं तो आपके पास कुछ गलत होने की संभावना है। यदि आप "अरे मैं शर्त लगाता हूं कि कोई भी 1 का उपयोग नहीं करता है" तो आपके ऑड्स छोटे से बड़े हैं। यह ठीक है क्योंकि हम सभी सोचते हैं कि 0 और 1 शांत हैं कि आपके पास उन्हें मारने की अधिक संभावना है।

-

जब आप serialVersionUID (1L) का उपयोग करने के बजाय serialVersionUID (3567653491060394677L) उत्पन्न करते हैं तो आप कुछ कह रहे हैं।

आप कह रहे हैं कि लोगों ने मैन्युअल रूप से इस वर्ग के इतिहास पर अन्य संस्करण संख्याएं बनाई या उत्पन्न की हैं और आपको परवाह नहीं है क्योंकि लोंग्स बड़ी संख्या में धोखाधड़ी कर रहे हैं।

किसी भी तरह से जब तक आप पूरी तरह से वर्जन संख्याओं के इतिहास को नहीं जानते हैं, जब वह पूरे ब्रह्मांड में कक्षा का उपयोग करता है, जहां उसका अस्तित्व है या कभी मौजूद होगा, तो आप एक मौका ले रहे हैं। यदि आपके पास 100% सुनिश्चित करने का समय है 1 AOK है, तो इसके लिए जाएं। यदि यह बहुत काम की है, तो आगे बढ़ें और नेत्रहीन संख्या उत्पन्न करें। आपको लॉटरी जीतने की संभावना अधिक है कि आप गलत हैं। अगर ऐसा होता है, तो मुझे बताएं और मैं आपको एक बीयर खरीदूंगा।

लॉटरी खेलने की इस सारी बात के साथ मैंने आपको यह आभास दिया होगा कि क्रमिक रूप से serialVersionUID उत्पन्न होता है। वास्तव में जब तक संख्याओं की श्रेणी समान रूप से एक लंबे समय के हर संभव मूल्य पर वितरित की जाएगी जो ठीक होगी। हालाँकि, यह वास्तव में इस तरह किया गया है:

http://docs.oracle.com/javase/6/docs/platform/serialization/spec/class.html#4100

एकमात्र अंतर जो आपको मिलता है वह यह है कि आपको यादृच्छिक के स्रोत की आवश्यकता नहीं है। आप परिणाम बदलने के लिए स्वयं कक्षा में हुए परिवर्तनों का उपयोग कर रहे हैं। लेकिन कबूतर के सिद्धांत के अनुसार अभी भी एक मौका है कि यह गलत हो सकता है और टकराव हो सकता है। यह सिर्फ अविश्वसनीय रूप से संभावना नहीं है। तो सौभाग्य है कि मुझे एक बीयर मिल रही है।

हालाँकि, भले ही वर्ग केवल एक प्रणाली और एक कोड आधार में रहेगा, यह सोचकर कि संख्या को हाथ से बढ़ाने से आपको टक्करों का शून्य मौका मिलता है, इसका मतलब है कि आप इंसानों को नहीं समझते हैं। :)


यदि कोई "सिस्टम" क्लास को छूता है, यानी क्लास को इस तरह से बदलता है कि क्रमबद्धता असंगत हो जाती है, तो सवाल यह है कि क्या यह सिस्टम सीरियलवर्जन यूआईडी को भी बदल देगा। मुझे नहीं लगता है कि ऑड्स छोटे हैं कि जब यह लंबा होगा तो इसे बदलना याद होगा। मुझे लगता है कि इसके विपरीत सच है, अगर संख्या को याद रखना आसान है कि बदलाव अधिक हैं तो मुझे लगता है कि मैंने गलती से इसे नहीं बदला।
रेटो गमर

2
यह गलत है! जब आप serialVersionUID जनरेट करते हैं, और 1L के बजाय अपने स्रोत कोड में उस मूल्य की घोषणा करते हैं, या कुछ भी नहीं जो आप वास्तव में कह रहे हैं: मैं भविष्य में अपरिभाषित प्रभावों के साथ संभवतः अनिर्धारित टकराव चाहता हूं, और मैं नहीं चाहता हूं कि जावा या कोई भी मनुष्य इसे रोकें। । जावा पागल है, लेकिन आज्ञाकारी है। मनुष्य आमतौर पर बड़ी संख्या में गड़बड़ नहीं करता है। इस तरह, जब कक्षा बदलती है, जावा अभी भी इसके पुराने असंगत संस्करणों को डी-सीरियल कर सकता है। मवहहा ...;)
सुपरोल

1

खैर, serialVersionUID नियम का एक अपवाद है कि "स्थिर क्षेत्रों को क्रमबद्ध नहीं किया जाता है"। ObjectOutputStream हर बार उत्पादन धारा में serialVersionUID का मान लिखता है। ObjectInputStream इसे वापस पढ़ता है और यदि धारा से पढ़ा गया मान वर्ग के वर्तमान संस्करण में serialVersionUID मान से सहमत नहीं है, तो यह InvalidClassException को फेंक देता है। इसके अलावा, अगर कोई सीरियलवर्ल्ड यूआईडी नहीं है, तो आधिकारिक तौर पर वर्ग में क्रमबद्ध घोषित किया जाता है, संकलक स्वचालित रूप से वर्ग में घोषित क्षेत्रों के आधार पर उत्पन्न मूल्य के साथ इसे जोड़ता है।


0

क्योंकि कई मामलों में डिफ़ॉल्ट आईडी अद्वितीय नहीं होती है। इसलिए हम अद्वितीय अवधारणा बनाने के लिए आईडी बनाते हैं।


क्या आप अपना जवाब दे सकते हैं कि इसे और अधिक मांस दें? यह यहाँ एक टिप्पणी की तरह लगता है। धन्यवाद।
ग्रे

0

@David Schmitts उत्तर में जोड़ने के लिए, अंगूठे के एक नियम के रूप में मैं हमेशा डिफ़ॉल्ट 1L सम्मेलन से बाहर का उपयोग करूंगा। मुझे केवल कुछ समय बाद वापस जाना है और उनमें से कुछ को बदलना है, लेकिन मुझे पता था कि जब मैंने बदलाव किया और हर बार डिफ़ॉल्ट नंबर को अपडेट किया।

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


0

क्रमबद्धकरण संस्करण UID का उद्देश्य वस्तुओं के वैध क्रमांकन करने के लिए एक वर्ग के विभिन्न संस्करणों पर नज़र रखना है।

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

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

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

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

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

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

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

यदि ऐसा है, तो सीरियलवर्जन यूआईडी = 1 एल सेट करें।

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

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

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

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