java معنى ما هو serialVersionUID ولماذا علي استخدامه؟




معنى كلمة عنوان بالانجليزي (17)

يمكنك إخبار Eclipse بتجاهل هذه التحذيرات serialVersionUID:

نافذة> تفضيلات> Java> مترجم> أخطاء / تحذيرات> مشاكل البرمجة المحتملة

في حالة عدم معرفتك ، هناك الكثير من التحذيرات الأخرى التي يمكنك تمكينها في هذا القسم (أو حتى أنه تم الإبلاغ عن بعض الأخطاء كأخطاء) ، كثير منها مفيد للغاية:

  • مشاكل البرمجة المحتملة: احتمالية منطقية عرضية محتملة
  • مشاكل البرمجة المحتملة: الوصول المؤشر فارغة
  • رمز غير ضروري: لا يتم قراءة المتغير المحلي مطلقًا
  • رمز غير ضروري: فحص فارغ بلا قيمة
  • رمز غير ضروري: إرسال غير ضروري أو "instanceof"

و أكثر من ذلك بكثير.

Eclipse يصدر تحذيرات عند فقد serialVersionUID .

لا يُعلن عن فئة Fino القابلة للتسلسل إعلان حقل serialVersionUID نهائي ثابت من النوع الطويل

ما هو serialVersionUID ولماذا هو مهم؟ الرجاء إظهار مثال حيث سيؤدي serialVersionUID المفقود إلى حدوث مشكلة.


serialVersionUID يسهل إصدار إصدارات البيانات المتسلسلة. يتم تخزين قيمته مع البيانات عند التسلسل. عند إلغاء التسلسل ، يتم فحص نفس الإصدار لمعرفة كيف تطابق البيانات المتسلسلة مع التعليمة البرمجية الحالية.

إذا كنت ترغب في إصدار نسخ من بياناتك ، فستبدأ عادةً بـ serialVersionUID من 0 ، serialVersionUID بكل تغيير هيكلي في الفصل الذي يغير البيانات المتسلسلة (إضافة أو إزالة حقول غير عابرة).

in.defaultReadObject() آلية إزالة التسلسل in.defaultReadObject() ( in.defaultReadObject() ) إزالة التسلسل من الإصدارات القديمة للبيانات. ولكن إذا كنت تريد أن تتمكن من تحديد وظيفة readObject() الخاصة بك والتي يمكن قراءة البيانات القديمة. يمكن بعد ذلك لهذه الشفرة المخصصة التحقق من serialVersionUID للتعرف على الإصدار الموجود في البيانات وتحديد كيفية serialVersionUID . تفيد تقنية تعيين الإصدارات هذه في حالة تخزين البيانات المتسلسلة التي تنجو من عدة إصدارات من التعليمات البرمجية.

ولكن تخزين البيانات المتسلسلة لفترة زمنية طويلة ليس شائعًا جدًا. من الأكثر شيوعًا استخدام آلية التسلسل في كتابة البيانات مؤقتًا إلى ذاكرة مؤقتة على سبيل المثال أو إرسالها عبر الشبكة إلى برنامج آخر باستخدام نفس الإصدار من الأجزاء ذات الصلة من مصدر البرمجة.

في هذه الحالة ، لن تكون مهتمًا بالحفاظ على التوافق مع الإصدارات السابقة. أنت مهتم فقط بالتأكد من أن القواعد البرمجية التي تقوم بالتواصل تمتلك بالفعل نفس الإصدارات من الفصول ذات الصلة. لتسهيل مثل هذا التحقق ، يجب عليك الحفاظ على serialVersionUID مثلما serialVersionUID قبل ، ولا تنس تحديثه عند إجراء تغييرات على الفصول الدراسية.

إذا نسيت تحديث الحقل ، فقد ينتهي بك الأمر إلى إصدارين مختلفين لفئة ذات بنية مختلفة ولكن مع نفس serialVersionUID . في حالة حدوث ذلك ، لن تكشف الآلية الافتراضية ( in.defaultReadObject() ) عن أي اختلاف ، وتحاول إلغاء تسلسل البيانات غير المتوافقة. الآن قد ينتهي الأمر مع خطأ وقت التشغيل خفي أو فشل صامت (حقول فارغة). قد يكون من الصعب العثور على هذه الأنواع من الأخطاء.

لذلك لمساعدة هذا usecase ، يوفر لك نظام Java اختيارًا لعدم تعيين serialVersionUID يدويًا. بدلاً من ذلك ، سيتم إنشاء تجزئة بنية الفصل في وقت الترجمة واستخدامها كمعرف. ستتأكد هذه الآلية من عدم وجود بنية فئة مختلفة بنفس معرفها ، وبالتالي لن تحصل على هذه الفشل في التسلسل الزمني الذي يصعب تتبعه والمشار إليه أعلاه.

ولكن هناك مؤخرًا لاستراتيجية المعرف التلقائي. أي أن معرّفات الفئة نفسها قد تختلف بين المعتمدين (كما ذكر جون سكيت أعلاه). لذلك إذا قمت بتوصيل البيانات المتسلسلة بين الشفرات التي تم تجميعها مع مترجمين مختلفين ، فمن المستحسن الحفاظ على أرقام التعريف يدويًا على أي حال.

وإذا كنت متوافقاً مع بياناتك كما في حالة الاستخدام الأولى المذكورة ، فمن المحتمل أيضًا أنك تريد الحفاظ على الهوية بنفسك. هذا من أجل الحصول على معرفات قابلة للقراءة وتحكم أكبر في وقت وكيفية تغييرها.


تمثل بيانات الحقل بعض المعلومات المخزنة في الفصل. تطبق الفئة واجهة Serializable ، لذلك تقدم الكسوف تلقائيا إلى الإعلان عن الحقل serialVersionUID . دعونا نبدأ مع القيمة 1 مجموعة هناك.

إذا كنت لا تريد أن يأتي هذا التحذير ، فاستخدم هذا:

@SuppressWarnings("serial")

إذا تلقيت هذا التحذير على صف لا تفكر فيه مطلقًا في التسلسل ، وأنك لم تعلن عن implements Serializable ، فغالبًا ما يكون ذلك بسبب ورثتك من الطبقة الفائقة ، التي تقوم بتنفيذ 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 أو هكذا ، عندما يحتاجون فقط إلى تفويض ذلك. (ويساعد هذا أيضًا على الإكمال التلقائي في بيئة تطوير متكاملة (IDE) ، نظرًا لأن JFrame به مئات من الطرق ، والتي لا تحتاجها عندما تريد الاتصال بأجهزتك المخصصة في صفك.)

حالة واحدة يكون فيها التحذير (أو serialVersionUID) لا يمكن تجنبه عند التمديد من AbstractAction ، عادةً في فئة مجهولة ، فقط بإضافة الإجراءأسلوب تنفيذ. أعتقد أنه لا ينبغي أن يكون هناك تحذير في هذه الحالة (بما أنه لا يمكنك عادةً إجراء تسلسل موثوق به وإلغاء تسلسل هذه الطبقات المجهولة على أية حال عبر إصدارات مختلفة من الفصل الدراسي الخاص بك) ، لكنني لست متأكداً من كيفية تعترف المحول البرمجي بذلك.


سيكون من الأفضل إذا كان CheckStyle يمكن أن يتحقق من أن serialVersionUID على فئة تقوم بتنفيذ Serializable له قيمة جيدة ، أي أنه يتطابق مع ما سينتجه مولد معرف الإصدار التسلسلي. إذا كان لديك مشروع به الكثير من DTOs القابلة للتسلسل ، على سبيل المثال ، تذكر حذف serialVersionUID الحالي وإعادة توليده هو ألم ، والطريقة الوحيدة حالياً (التي أعرفها) للتحقق من ذلك هي التجديد لكل فئة ومقارنتها القديم. هذا مؤلم جدا جدا.


من المحتمل أن تكون مستندات java.io.Serializable جيدة كشرح كما ستحصل عليه:

يربط وقت التشغيل بالتسلسل مع كل فئة serialVersionUID للتسلسل رقم إصدار ، يسمى serialVersionUID ، والذي يتم استخدامه أثناء إلغاء التسلسل للتحقق من أن المرسل والمتلقي لكائن متسلسل قاما بتحميل فئات لهذا الكائن متوافقة مع التسلسل. إذا كان المستلم قد قام بتحميل فئة للكائن الذي له serialVersionUID مختلف عن فئة المرسل المقابلة ، فإن إلغاء التسلسل سيؤدي إلى InvalidClassException . يمكن لفئة serialVersionUID للتسلسل أن تعلن عن serialVersionUID الخاص بها صراحة عن طريق التصريح بحقل باسم serialVersionUID والذي يجب أن يكون ثابتًا ونهائيًا ونوع long :

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

إذا لم تعلن فئة قابلة للتسلسل صراحةً serialVersionUID ، serialVersionUID وقت التشغيل التسلسلي قيمة serialVersionUID افتراضية لتلك الفئة بناءً على جوانب مختلفة من الفئة ، كما هو موصوف في مواصفات تسلسل كائن Java (TM). ومع ذلك ، فمن المستحسن بشدة أن تعلن جميع الفئات serialVersionUID للتسلسل صراحةً قيم serialVersionUID ، نظرًا لأن الحساب الافتراضي serialVersionUID حساس للغاية لتفاصيل الفئة التي قد تختلف بناءً على تطبيقات المترجم ، وبالتالي يمكن أن يؤدي إلى InvalidClassExceptions غير متوقع أثناء إلغاء التسلسل. لذلك ، لضمان قيمة serialVersionUID متسقة عبر تطبيقات مترجم java مختلفة ، يجب أن تعلن فئة قابلة serialVersionUID قيمة serialVersionUID صريحة. كما يُنصح بشدة أن تستخدم تعريفات serialVersionUID الواضحة serialVersionUID الخاص كلما كان ذلك ممكناً ، حيث أن هذه التعريفات تنطبق فقط على حقول serialVersionUID الفصل serialVersionUID فورًا ليست مفيدة كأعضاء serialVersionUID .


في كل مرة يتم فيها تسلسل كائن ، يتم ختم الكائن برقم معرف الإصدار serialVersionUID هذا الرقم اسم serialVersionUID ويتم حسابه استنادًا إلى معلومات حول بنية الفئة. لنفترض أنك قمت بعمل فئة موظف ولديها إصدار معرف # 333 (تم تعيينه بواسطة JVM) ، والآن عندما تقوم بتسلسل كائن تلك الفئة (افترض كائن الموظف) ، سيقوم JVM بتعيين UID له كـ # 333.

ضع في اعتبارك حالة - في المستقبل تحتاج إلى تعديل صفك أو تغييره ، وفي هذه الحالة عند تعديله ، سوف تقوم JVM بتعيينه UID جديد (لنفترض # 444). الآن عند محاولة إلغاء تسلسل كائن الموظف ، سيقوم JVM بمقارنة معرف الإصدار (كائن الموظف) المتسلسل للكائن المتسلسل (# 333) مع ذلك من الفئة ie # 444 (منذ أن تم تغييره). في المقارنة سوف تجد JVM كلا الإصدار UID مختلفة ، وبالتالي سوف تفشل إلغاء التسلسل. ومن ثم إذا تم تعريف serialVersionID لكل فئة من قبل مبرمج نفسه. سيكون نفس الشيء حتى إذا تم تطوير الفئة في المستقبل وبالتالي سيجد JVM دائمًا أن الفئة متوافقة مع الكائن المتسلسل على الرغم من تغيير الفئة. لمزيد من المعلومات ، يمكنك الرجوع إلى الفصل 14 من HEAD FIRST JAVA.


لماذا استخدام SerialVersionUIDداخل Serializableالطبقة في جاوة؟

وأثناء ذلك serialization، يُنشئ وقت التشغيل في جافا رقم إصدار لفئة ، بحيث يمكن إلغاء تسلسلها لاحقًا. يعرف رقم الإصدار هذا SerialVersionUIDفي Java.

SerialVersionUIDيستخدم لإصدار البيانات المتسلسلة. يمكنك فقط فصل تسلسل فصل دراسي إذا كان SerialVersionUIDيتطابق مع النسخة المتسلسلة. عندما لا نعلن SerialVersionUIDفي صفنا ، فإن وقت تشغيل Java يولده لنا ولكن لا يوصى به. من المستحسن أن يعلن SerialVersionUIDكما private static final longمتغير لتجنب آلية الافتراضية.

عندما تقوم بتعريف فئة من Serializableخلال تنفيذ واجهة علامة java.io.Serializable، فإن وقت تشغيل Java يستمر مثيلًا لذلك الفصل إلى القرص باستخدام آلية التسلسل الافتراضية ، بشرط ألا تقوم بتخصيص العملية باستخدام Externalizableالواجهة.

انظر أيضا لماذا استخدام SerialVersionUID داخل فئة Serializable في جاوة

الرمز: javassist.SerialVersionUID


إذا لم تكن بحاجة إلى تسلسل الأشياء الخاصة بك إلى صفيف البايت وإرسالها / تخزينها ، فلا داعي للقلق بشأنها. إذا قمت بذلك ، فيجب أن تفكر في serialVersionUID نظرًا لأن deserializer للكائن سيتم مطابقته مع إصدار الكائن الذي يحمله classloader. اقرأ المزيد عنها في مواصفات لغة Java.


لفهم أهمية الحقل serialVersionUID ، يجب أن يفهم المرء كيف يعمل التسلسل / إلغاء التجفير.

عند تسلسل كائن فئة Serializable ، يقوم Java Runtime بربط نسخة تسلسلية (تسمى serialVersionUID) بهذا الكائن المسلسل. في الوقت الذي يتم فيه إلغاء تسلسل هذا الكائن المتسلسل ، يتطابق Java Runtime مع serialVersionUID للكائن المتسلسل مع serialVersionUID للفئة. إذا كان كلاهما متساويين ، فحينئذ فقط يستمر في عملية إلغاء التسلسل الأخرى ، حيث يرمي InvalidClassException.

لذلك نستنتج أن عملية Serialization / Deserialization ناجحة يجب أن يكون serialVersionUID للكائن المتسلسل مساوياً لـ serialVersionUID للفئة. في حالة تحديد المبرمج لقيمة serialVersionUID بشكل صريح في البرنامج ، فسيتم إقران نفس القيمة مع الكائن المتسلسل والفئة ، بغض النظر عن النظام الأساسي للتسلسل وإلغاء النظام (قد يتم إجراء التسلسل السابق على النظام الأساسي مثل النوافذ باستخدام الشمس أو قد يكون MS JVM و Deserialization على نظام Linux مختلف باستخدام Zing JVM).

ولكن في حالة إذا لم يتم تحديد serialVersionUID من قبل مبرمج ثم أثناء إجراء Serialization \ DeSerialization لأي كائن ، يستخدم وقت التشغيل Java الخوارزمية الخاصة به لحسابه. تختلف خوارزمية الحساب serialVersionUID هذه من JRE إلى أخرى. من الممكن أيضًا أن البيئة التي يتم فيها إجراء التسلسل باستخدام JRE (على سبيل المثال: SUN JVM) والبيئة التي يحدث فيها إلغاء التجميع تستخدم Linux Jvm (zing). في مثل هذه الحالات ، سيكون serialVersionUID المرتبط بالعنصر المتسلسل مختلفًا عن serialVersionUID للفئة المحسوبة في بيئة إلغاء التجفير. بدوره لن يكون إلغاء التسلط ناجحا. لتجنب هذه الحالات / القضايا يجب أن يحدد المبرمج دائما serialVersionUID للفئة Serializable.


أولا أنا بحاجة إلى شرح التسلسل.
يسمح التسلسل بتحويل الكائن إلى دفق ، لإرسال هذا الكائن عبر الشبكة أو حفظ إلى ملف أو حفظ في قاعدة بيانات لاستخدام الحرف.

هناك بعض القواعد للتسلسل .

  • يكون عنصرًا قابلاً للتسلسل فقط إذا كان صنفه أو فئته المميزة ينفذ الواجهة التسلسلية

  • كائن قابل للتسلسل (في حد ذاته يطبق واجهة Serializable) حتى إذا كانت الطبقة المميزة ليست كذلك. ومع ذلك ، يجب أن يكون superclass الأول في التسلسل الهرمي للفئة serializable ، التي لا تطبق واجهة Serializable ، منشئ بدون - arg. إذا تم انتهاك هذا ، فسوف ينتج readObject () java.io.InvalidClassException في وقت التشغيل

  • جميع الأنواع البدائية قابلة للتسلسل.

  • لا يتم إجراء تسلسل للحقول العابرة (مع معدّل عابر) (أي لم يتم حفظها أو استعادتها). يجب على الفئة التي تقوم بتطبيق Serializable أن تضع علامة على الحقول المؤقتة للفئات التي لا تدعم التسلسل (على سبيل المثال ، تدفق الملف).

  • الحقول الثابتة (مع معدّل ثابت) هي غير متسلسلة.

عندما يكون الكائن Serialized JAVA Runtime Associates رقم الإصدار التسلسلي الذي يسمى serialVersionID.

حيث نحتاج إلى serialVersionID: أثناء إلغاء التسلسل للتحقق من أن المرسل والمستقبل متوافقان فيما يتعلق بالتسلسل.إذا قام المستلم بتحميل الفئة بمسلسلات مختلفة ، فسيتم إنهاء إلغاء التسلسل باستخدام 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");
}
}

Deserializ الكائن

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

ملاحظة: الآن تغيير serialVersionUID من فئة الموظف وحفظ:

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)

أنا عموما استخدام serialVersionUID في سياق واحد: عندما أعلم أنه سيتم ترك سياق جافا VM.

أعرف ذلك عندما أستخدم ObjectInputStream و ObjectOutputStream للتطبيق الخاص بي أو إذا كنت أعرف أن المكتبة / الإطار الذي أستخدمه سوف يستخدمونه. يضمن serialVersionID مختلف Java VMs من إصدارات مختلفة أو سوف يتفاعل الباعة بشكل صحيح أو إذا تم تخزينه واسترجاعه خارج VM على سبيل المثال HttpSession ، يمكن أن تظل بيانات الجلسة حتى أثناء إعادة تشغيل وترقية خادم التطبيق.

لجميع الحالات الأخرى ، وأنا استخدم

@SuppressWarnings("serial")

منذ معظم الوقت الافتراضي serialVersionUID كافية. وهذا يشمل Exception ، HttpServlet .


ما هو serialVersionUID ولماذا علي استخدامه؟

SerialVersionUID هو معرف فريد لكل فصل ، JVM تستخدمه لمقارنة إصدارات الفئة التي تضمن أن نفس الفئة تم استخدامها أثناء عملية Serialization أثناء تحميل Deserialization.

يعطي تحديد واحد المزيد من التحكم ، على الرغم من أن JVM تقوم بإنشاء واحد إذا لم تقم بتحديده. يمكن للقيمة المتولدة أن تختلف بين المجمعين المختلفين. وعلاوة على ذلك ، في بعض الأحيان كنت ترغب فقط لسبب ما لمنع تجريد الكائنات المتسلسلة القديمة [ backward incompatibility ] ، وفي هذه الحالة عليك فقط تغيير serialVersionUID.

يقول javadocs عن Serializable :

الحساب الافتراضي serialVersionUID حساس للغاية لتفاصيل الفئة التي قد تختلف اعتمادًا على تطبيقات المحول البرمجي ، وبالتالي يمكن أن ينتج عن InvalidClassException غير متوقع أثناء إلغاء التسلسل.

لذلك ، يجب عليك أن تعلن serialVersionUID لأنه يمنحنا المزيد من التحكم .

تحتوي هذه المقالة على بعض النقاط الجيدة حول الموضوع.


لا تهتم ، الحساب الافتراضي هو جيد حقا وتكفي 99،9999 ٪ من الحالات. وإذا واجهت مشاكل ، يمكنك - كما ذكر سابقاً - إدخال تعريف UID كضرورة (وهو أمر مستبعد للغاية)


إذا كنت ترغب في تعديل عدد كبير من الفئات التي لم يتم تعيين serialVersionUID في المقام الأول مع الحفاظ على التوافق مع الطبقات القديمة ، فإن أدوات مثل IntelliJ Idea ، Eclipse تقع قصيرة لأنها تولد أرقام عشوائية ولا تعمل على مجموعة من الملفات خلال مرة واحدة. لقد قمت بكتابة البرنامج النصي bash التالي (أنا آسف لمستخدمي Windows ، فكر في شراء جهاز Mac أو التحويل إلى Linux) لإصلاح مسألة serialVersionUID بسهولة:

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. ثم قمت بتشغيلها في الدليل الجذر لمشروع Maven أو Gradle مثل:

add_serialVersionUID.sh < myJavaToAmend.lst

يتضمن هذا .lst قائمة ملفات java لإضافة serialVersionUID بالتنسيق التالي:

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 / bin في PATH.


هذا السؤال موثق جيدًا في جاوة الفعالة بقلـم جوشوا بلوخ. كتاب جيد جدا ويجب أن يقرأ. سأوجز بعض الأسباب أدناه:

يأتي وقت التشغيل التسلسلي مع رقم يسمى الإصدار التسلسلي لكل فئة قابلة للتسلسل. يسمى هذا الرقم serialVersionUID. الآن هناك بعض الرياضيات وراء هذا الرقم ويخرج على أساس الحقول / الأساليب التي تم تعريفها في الفصل. لنفس الفئة يتم إنشاء نفس الإصدار في كل مرة. يستخدم هذا الرقم أثناء إلغاء التسلسل للتحقق من أن المرسل والمتلقي لكائن متسلسل قاما بتحميل فئات لهذا الكائن متوافقة مع التسلسل. إذا كان المستلم قد قام بتحميل فئة للكائن الذي له serialVersionUID مختلف عن فئة المرسل المقابلة ، فإن إلغاء التسلسل سيؤدي إلى InvalidClassException.

إذا كان الفصل قابل للتسلسل ، يمكنك أيضًا تعريف serialVersionUID الخاص بك بشكل صريح من خلال التصريح بحقل باسم "serialVersionUID" يجب أن يكون ثابتًا ونهائيًا ونوعًا طويلاً. معظم IDE مثل Eclipse يساعدك على توليد هذه السلسلة الطويلة.


بالنسبة إلى مثال حيث قد يسبب serialVersionUID المفقود مشكلة:

أعمل على تطبيق Java EE هذا ويتكون من وحدة نمطية على الويب تستخدم وحدة EJB . تستدعي وحدة الويب وحدة EJB عن بُعد وتمرير POJO بتنفيذ Serializable كوسيطة.

تم تعبئة صنف POJO's داخل جرة EJB وداخل جرة خاصة به في WEB-INF / lib لوحدة الويب. إنهم في الواقع نفس الفصل ، لكن عندما أحزم وحدة EJB ، أقوم بتفريغ جرة بوجو هذه لكي نجمعها مع وحدة EJB.

فشل الاتصال بـ EJB مع Exception أدناه لأنني لم أعلن عن 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




serialversionuid