מהו serialVersionUID?

1. סקירה כללית

פשוט שים, ה serialVersionUID הוא מזהה ייחודי עבור ניתן לבצע סדרתי שיעורים.

זה משמש במהלך עריקת ערעור של אובייקט, כדי להבטיח שמחלקה טעונה תואמת לאובייקט הסדרתי. אם לא נמצא כיתה תואמת, InvalidClassException נזרק.

2. גרסה טורית UID

נתחיל ביצירת מחלקה מסודרת ונכריז על a serialVersionUID מזהה:

מחלקה ציבורית AppleProduct מיישמת Serializable {פרטית סטטית פרטית סופית ארוכה serialVersionUID = 1234567L; אוזניות מיתרים פומביות נמל; רעם מחרוזת ציבורי נמל; }

בשלב הבא נצטרך שתי מחלקות עזר: האחת לסידור סדרתי של AppleProduct חפץ לתוך חוּט, ואחרת לנטרל את האובייקט מזה חוּט:

Class class SerializationUtility {public static void main (String [] args) {AppleProduct macBook = AppleProduct new (); macBook.headphonePort = "headphonePort2020"; macBook.thunderboltPort = "thunderboltPort2020"; מחרוזת serializedObj = serializeObjectToString (macBook); System.out.println ("אובייקט AppleProduct מסודר למחרוזת:"); System.out.println (serializedObj); } מחרוזת סטטית ציבורית serializeObjectToString (Serializable o) {ByteArrayOutputStream baos = ByteArrayOutputStream חדש (); ObjectOutputStream oos = ObjectOutputStream חדש (baos); oos.writeObject (o); oos.close (); החזר Base64.getEncoder (). encodeToString (baos.toByteArray ()); }}
מחלקה ציבורית DeserializationUtility {public static void main (String [] args) {String serializedObj = ... // הופסל לשם הבהירות System.out.println ("Deserializing AppleProduct ..."); AppleProduct deserializedObj = (AppleProduct) deSerializeObjectFromString (serializedObj); System.out.println ("יציאת האוזניות של AppleProduct:" + deserializedObj.getHeadphonePort ()); System.out.println ("יציאת Thunderbolt של AppleProduct:" + deserializedObj.getThunderboltPort ()); } אובייקט סטטי ציבורי deSerializeObjectFromString (String s) זורק IOException, ClassNotFoundException {byte [] data = Base64.getDecoder (). decode (s); ObjectInputStream ois = חדש ObjectInputStream (ByteArrayInputStream חדש (נתונים)); אובייקט o = ois.readObject (); ois.close (); החזר o; }}

אנחנו מתחילים בריצה SerializationUtility.java, אשר חוסך (מסדר) את AppleProduct חפץ לתוך חוּט instancה, קידוד בתים באמצעות Base64.

ואז, באמצעות זה חוּט כטיעון לשיטת התנערות, אנו רצים DeserializationUtility.java, שמרכיב מחדש (מבטל את ההתפשטות) של AppleProduct אובייקט מהנתון חוּט.

הפלט שנוצר צריך להיות דומה לזה:

AppleProduct בהמשכים אובייקט מחרוזת: rO0ABXNyACljb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkFwcGxlUHJvZHVjdAAAAAAAEta HAgADTAANaGVhZHBob25lUG9ydHQAEkxqYXZhL2xhbmcvU3RyaW5nO0wADmxpZ2h0ZW5pbmdQb3 J0cQB + AAFMAA90aHVuZGVyYm9sdFBvcnRxAH4AAXhwdAARaGVhZHBob25lUG9ydDIwMjBwdAATd Gh1bmRlcmJvbHRQb3J0MjAyMA ==
ביטול ערעור של AppleProduct ... יציאת אוזניות של Apple מוצר: אוזניות Port2020 יציאת Thunderbolt של Apple מוצר: thunderboltPort2020

עכשיו, בואו ונשנה את ה- serialVersionUIDקבוע ב AppleProduct.java, ולנסות מחדש לערוק ה AppleProduct אובייקט מאותו מחרוזת שהופק קודם לכן. רץ מחדש DeserializationUtility.java צריך לייצר תפוקה זו.

ביטול ערעור AppleProduct ... יוצא מן הכלל בחוט "הראשי" java.io.InvalidClassException: com.baeldung.deserialization.AppleProduct; מחלקה מקומית אינה תואמת: זרם classdesc serialVersionUID = 1234567, מחלקה מקומית serialVersionUID = 7654321 ב- java.io.ObjectStreamClass.initNonProxy (ObjectStreamClass.java:616) ב- java.io.ObjectInputStream.readNonProxyDesc (ObjectInputStream.java .16. ObjectInputStream.readClassDesc (ObjectInputStream.java:1521) ב- java.io.ObjectInputStream.readOrdinaryObject (ObjectInputStream.java:1781) ב- java.io.ObjectInputStream.readObject0 (ObjectInputStream.java:1353) ב- java.io.OmjectStream.ObjectInput .java: 373) ב- com.baeldung.deserialization.DeserializationUtility.deSerializeObjectFromString (DeserializationUtility.java:24) ב- com.baeldung.deserialization.DeserializationUtility.main (DeserializationUtility.java:15)

על ידי שינוי ה- serialVersionUID של הכיתה, שינינו את הגרסה / מצב שלה. כתוצאה מכך, לא נמצאו שיעורים תואמים במהלך התנערות, ו InvalidClassException נזרק.

3. שינויים תואמים

נניח שעלינו להוסיף שדה חדש נמל ברקים לקיים שלנו AppleProduct מעמד:

מחלקה ציבורית AppleProduct מיישמת Serializable {// ... public String lightningPort; }

מכיוון שאנו רק מוסיפים שדה חדש, אין שינוי ב- serialVersionUID יידרש. זה בגלל ש, במהלך תהליך העריקה ריק יוקצה כערך ברירת המחדל עבור ה- נמל ברקים שדה.

בואו נשנה את שלנו Deserialization שימוש בכיתה להדפסת הערך של שדה חדש זה:

System.out.println ("יציאת LightningPort של AppleProduct:" + deserializedObj.getLightningPort ());

עכשיו, כשאנחנו מריצים מחדש את Deserialization שימוש בכיתה, נראה פלט הדומה ל:

ביטול ערעור AppleProduct ... יציאת אוזניות של Apple מוצר: אוזניות Port2020 יציאת Thunderbolt של Apple מוצר: thunderbolt Port2020 יציאת ברק של Apple מוצר: null

4. גרסת ברירת מחדל סדרתית

אם אנחנו לא מגדירים א serialVersionUID מדינה עבור א ניתן לבצע סדרתי מחלקה, ואז ג'אווה תגדיר אחת על סמך מאפיינים מסוימים של המחלקה עצמה כגון שם המחלקה, שדות מופע וכו '.

בואו נגדיר פשוט ניתן לבצע סדרתי מעמד:

מחלקה ציבורית DefaultSerial מיישמת ניתנת לסידור {}

אם אנו מסדרים מופע של מחלקה זו באופן הבא:

מופע DefaultSerial = DefaultSerial חדש (); System.out.println (SerializationUtility.serializeObjectToString (מופע));

פעולה זו תדפיס את עיכול Base64 של הסדרה הבינארית הסדרתית:

rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpYWxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw

בדיוק כמו בעבר, אנו אמורים להיות מסוגלים לבטל את הערכת המופע הזה מעיכול:

מחרוזת לעכל = "rO0ABXNyACpjb20uYmFlbGR1bmcuZGVzZXJpY" + "WxpemF0aW9uLkRlZmF1bHRTZXJpYWx9iVz3Lz / mdAIAAHhw"; מופע DefaultSerial = (DefaultSerial) DeserializationUtility.deSerializeObjectFromString (digest);

עם זאת, שינויים מסוימים בכיתה זו עלולים לשבור את תאימות הסידור. למשל, אם נוסיף א פְּרָטִי שדה לכיתה זו:

מחלקה ציבורית DefaultSerial מיישמת באמצעות Serializable {שם מחרוזת פרטי; }

ואז נסה לבטל את עריכת אותה תקציר Base64 למופע מחלקה, נקבל InvalidClassException:

חריג בשרשור "הראשי" java.io.InvalidClassException: com.baeldung.deserialization.DefaultSerial; מחלקה מקומית אינה תואמת: זרם classdesc serialVersionUID = 9045863543269746292, מחלקה מקומית serialVersionUID = -2692722436255640434

בגלל סוג כזה של חוסר תאימות לא רצוי, זה תמיד רעיון טוב להכריז על serialVersionUID ב ניתן לבצע סדרתי שיעורים. בדרך זו אנו יכולים לשמור או לפתח את הגרסה ככל שהכיתה עצמה מתפתחת.

5. מסקנה

במאמר מהיר זה הדגמנו את השימוש ב- serialVersionUID קבוע כדי להקל על גרסאות של נתונים סדרתיים.

כמו תמיד, ניתן למצוא את דגימות הקוד המשמשות לאורך מאמר זה באתר GitHub.