java - ترجمة - معنى كلمة عنوان بالانجليزي
ما هو serialVersionUID ولماذا علي استخدامه؟ (14)
ما هو serialVersionUID ولماذا علي استخدامه؟
SerialVersionUID
هو معرف فريد لكل فصل ، JVM
تستخدمه لمقارنة إصدارات الفئة التي تضمن أن نفس الفئة تم استخدامها أثناء عملية Serialization أثناء تحميل Deserialization.
يعطي تحديد واحد المزيد من التحكم ، على الرغم من أن JVM تقوم بإنشاء واحد إذا لم تقم بتحديده. يمكن للقيمة المتولدة أن تختلف بين المجمعين المختلفين. وعلاوة على ذلك ، في بعض الأحيان كنت ترغب فقط لسبب ما لمنع تجريد الكائنات المتسلسلة القديمة [ backward incompatibility
] ، وفي هذه الحالة عليك فقط تغيير serialVersionUID.
يقول javadocs عن Serializable
:
الحساب الافتراضي serialVersionUID حساس للغاية لتفاصيل الفئة التي قد تختلف اعتمادًا على تطبيقات المحول البرمجي ، وبالتالي يمكن أن ينتج عن
InvalidClassException
غير متوقع أثناء إلغاء التسلسل.
لذلك ، يجب عليك أن تعلن serialVersionUID لأنه يمنحنا المزيد من التحكم .
تحتوي هذه المقالة على بعض النقاط الجيدة حول الموضوع.
Eclipse يصدر تحذيرات عند فقد serialVersionUID
.
لا يُعلن عن فئة Fino القابلة للتسلسل إعلان حقل serialVersionUID نهائي ثابت من النوع الطويل
ما هو serialVersionUID
ولماذا هو مهم؟ الرجاء إظهار مثال حيث سيؤدي serialVersionUID
المفقود إلى حدوث مشكلة.
أنا عموما استخدام serialVersionUID
في سياق واحد: عندما أعلم أنه سيتم ترك سياق جافا VM.
أعرف ذلك عندما أستخدم ObjectInputStream
و ObjectOutputStream
للتطبيق الخاص بي أو إذا كنت أعرف أن المكتبة / الإطار الذي أستخدمه سوف يستخدمونه. يضمن serialVersionID مختلف Java VMs من إصدارات مختلفة أو سوف يتفاعل الباعة بشكل صحيح أو إذا تم تخزينه واسترجاعه خارج VM على سبيل المثال HttpSession
، يمكن أن تظل بيانات الجلسة حتى أثناء إعادة تشغيل وترقية خادم التطبيق.
لجميع الحالات الأخرى ، وأنا استخدم
@SuppressWarnings("serial")
منذ معظم الوقت الافتراضي serialVersionUID
كافية. وهذا يشمل Exception
، HttpServlet
.
إذا تلقيت هذا التحذير على صف لا تفكر فيه مطلقًا في التسلسل ، وأنك لم تعلن عن 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 ، عادةً في فئة مجهولة ، فقط بإضافة الإجراءأسلوب تنفيذ. أعتقد أنه لا ينبغي أن يكون هناك تحذير في هذه الحالة (بما أنه لا يمكنك عادةً إجراء تسلسل موثوق به وإلغاء تسلسل هذه الطبقات المجهولة على أية حال عبر إصدارات مختلفة من الفصل الدراسي الخاص بك) ، لكنني لست متأكداً من كيفية تعترف المحول البرمجي بذلك.
إذا كنت تقوم بالتسلسل لمجرد أنك تحتاج إلى التسلسل من أجل تطبيق التنفيذ (من يهتم إذا قمت بالتسلسل من أجل HTTPSession ، على سبيل المثال ... إذا تم تخزينه أو لا ، ربما لا يهمك إزالة تسلسل كائن النموذج) ، ثم يمكنك تجاهل هذا.
إذا كنت تستخدم التسلسل بالفعل ، فلا يهمك إلا إذا كنت تخطط لتخزين واسترجاع الكائنات باستخدام التسلسل مباشرةً. يمثل serialVersionUID إصدار الفئة ، ويجب زيادة ذلك إذا لم يكن الإصدار الحالي للفصل متوافقًا مع إصداره السابق.
في معظم الأحيان ، ربما لن تستخدم التسلسل مباشرةً. إذا كانت هذه هي الحالة ، فقم بإنشاء ملف uid افتراضي قابل للتسلسل عن طريق النقر فوق خيار الإصلاح السريع ولا تقلق بشأنه.
بالنسبة إلى مثال حيث قد يسبب 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
تمثل بيانات الحقل بعض المعلومات المخزنة في الفصل. تطبق الفئة واجهة Serializable
، لذلك تقدم الكسوف تلقائيا إلى الإعلان عن الحقل serialVersionUID
. دعونا نبدأ مع القيمة 1 مجموعة هناك.
إذا كنت لا تريد أن يأتي هذا التحذير ، فاستخدم هذا:
@SuppressWarnings("serial")
لا أستطيع أن أغتنم هذه الفرصة لسد كتاب جوش بلوخ " جافا الفعال" (الإصدار الثاني). الفصل 11 هو مورد لا غنى عنه في تسلسل جافا.
لكل Josh ، يتم إنشاء UID الذي يتم إنشاؤه تلقائيًا استنادًا إلى اسم الفئة ، واجهات التطبيق ، وجميع الأعضاء العامين والمحميين. تغيير أي من هذه بأي طريقة سوف يغير serialVersionUID
. لذلك لا تحتاج إلى الفوضى معهم إلا إذا كنت متأكداً من أنه لن يتم نسخ أكثر من نسخة واحدة للفصل (سواء عبر العمليات أو استردادها من التخزين في وقت لاحق).
إذا كنت تتجاهلها الآن ، وتجد لاحقًا أنك تحتاج إلى تغيير الفصل بطريقة ما مع الحفاظ على التوافق مع إصدار قديم للفئة ، فيمكنك استخدام الأداة التسلسلية لأداة JDK لإنشاء serialVersionUID
على الفئة القديمة ، وتعيينها بشكل صريح هذا على الطبقة الجديدة. (اعتمادًا على التغييرات التي writeObject
، قد تحتاج أيضًا إلى تنفيذ عملية تسلسل مخصصة عن طريق إضافة أساليب writeObject
و readObject
- راجع javadoc Serializable
أو الفصل 11 السابق ذكره).
لا تهتم ، الحساب الافتراضي هو جيد حقا وتكفي 99،9999 ٪ من الحالات. وإذا واجهت مشاكل ، يمكنك - كما ذكر سابقاً - إدخال تعريف UID كضرورة (وهو أمر مستبعد للغاية)
من المحتمل أن تكون مستندات 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
.
يمكنك إخبار Eclipse بتجاهل هذه التحذيرات serialVersionUID:
نافذة> تفضيلات> Java> مترجم> أخطاء / تحذيرات> مشاكل البرمجة المحتملة
في حالة عدم معرفتك ، هناك الكثير من التحذيرات الأخرى التي يمكنك تمكينها في هذا القسم (أو حتى أنه تم الإبلاغ عن بعض الأخطاء كأخطاء) ، كثير منها مفيد للغاية:
- مشاكل البرمجة المحتملة: احتمالية منطقية عرضية محتملة
- مشاكل البرمجة المحتملة: الوصول المؤشر فارغة
- رمز غير ضروري: لا يتم قراءة المتغير المحلي مطلقًا
- رمز غير ضروري: فحص فارغ بلا قيمة
- رمز غير ضروري: إرسال غير ضروري أو "instanceof"
و أكثر من ذلك بكثير.
لماذا استخدام 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 يستخدم للتحكم في النسخ للكائن. يمكنك تحديد serialVersionUID في ملف صفك أيضًا. نتيجة عدم تحديد serialVersionUID هو أنه عند إضافة أو تعديل أي حقل في الفئة ، فلن تكون الفئة المتسلسلة بالفعل قادرة على الاسترداد لأن serialVersionUID الذي تم إنشاؤه لفئة جديدة وللعنصر القديم المتسلسل سيكون مختلفًا. تعتمد عملية التسلسل في Java على serialVersionUID الصحيح لاستعادة حالة الكائن المتسلسل وإلقاء java.io.InvalidClassException في حالة عدم تطابق serialVersionUID
اقرأ المزيد: http://javarevisited.blogspot.com/2011/04/top-10-java-serialization-interview.html#ixzz3VQxnpOPZ
سيكون من الأفضل إذا كان CheckStyle يمكن أن يتحقق من أن serialVersionUID على فئة تقوم بتنفيذ Serializable له قيمة جيدة ، أي أنه يتطابق مع ما سينتجه مولد معرف الإصدار التسلسلي. إذا كان لديك مشروع به الكثير من DTOs القابلة للتسلسل ، على سبيل المثال ، تذكر حذف serialVersionUID الحالي وإعادة توليده هو ألم ، والطريقة الوحيدة حالياً (التي أعرفها) للتحقق من ذلك هي التجديد لكل فئة ومقارنتها القديم. هذا مؤلم جدا جدا.
في كل مرة يتم فيها تسلسل كائن ، يتم ختم الكائن برقم معرف الإصدار serialVersionUID هذا الرقم اسم serialVersionUID ويتم حسابه استنادًا إلى معلومات حول بنية الفئة. لنفترض أنك قمت بعمل فئة موظف ولديها إصدار معرف # 333 (تم تعيينه بواسطة JVM) ، والآن عندما تقوم بتسلسل كائن تلك الفئة (افترض كائن الموظف) ، سيقوم JVM بتعيين UID له كـ # 333.
ضع في اعتبارك حالة - في المستقبل تحتاج إلى تعديل صفك أو تغييره ، وفي هذه الحالة عند تعديله ، سوف تقوم JVM بتعيينه UID جديد (لنفترض # 444). الآن عند محاولة إلغاء تسلسل كائن الموظف ، سيقوم JVM بمقارنة معرف الإصدار (كائن الموظف) المتسلسل للكائن المتسلسل (# 333) مع ذلك من الفئة ie # 444 (منذ أن تم تغييره). في المقارنة سوف تجد JVM كلا الإصدار UID مختلفة ، وبالتالي سوف تفشل إلغاء التسلسل. ومن ثم إذا تم تعريف serialVersionID لكل فئة من قبل مبرمج نفسه. سيكون نفس الشيء حتى إذا تم تطوير الفئة في المستقبل وبالتالي سيجد JVM دائمًا أن الفئة متوافقة مع الكائن المتسلسل على الرغم من تغيير الفئة. لمزيد من المعلومات ، يمكنك الرجوع إلى الفصل 14 من HEAD FIRST JAVA.