سؤال

في جاوة، إذا كانت فئة تنفذ تسلسل ولكنها مجردة، فيجب أن يكون لديك serialversionuid منذ فترة طويلة، أو هل تتطلب الفئات الفرعية فقط ذلك؟

في هذه الحالة، من النية بالفعل أن جميع الفئات الفرعية تتعامل مع التسلسل حيث يتم استخدام الغرض من النوع في مكالمات RMI.

هل كانت مفيدة؟

المحلول

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

(بالطبع، يقوم بتوليد تحذير مترجم، الذي تريد التخلص منه، أليس كذلك؟)

اتضح أن تعليق جيمس هو الصحيح. SerialVersionUID من فئة قاعدة مجردة هل الحصول على نشر إلى الفئات الفرعية. في ضوء ذلك، أنت فعل بحاجة إلى serialversionuid في فئتك الأساسية.

رمز لاختبار:

import java.io.Serializable;

public abstract class Base implements Serializable {

    private int x = 0;
    private int y = 0;

    private static final long serialVersionUID = 1L;

    public String toString()
    {
        return "Base X: " + x + ", Base Y: " + y;
    }
}



import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class Sub extends Base {

    private int z = 0;

    private static final long serialVersionUID = 1000L;

    public String toString()
    {
        return super.toString() + ", Sub Z: " + z;
    }

    public static void main(String[] args)
    {
        Sub s1 = new Sub();
        System.out.println( s1.toString() );

        // Serialize the object and save it to a file
        try {
            FileOutputStream fout = new FileOutputStream("object.dat");
            ObjectOutputStream oos = new ObjectOutputStream(fout);
            oos.writeObject( s1 );
            oos.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        Sub s2 = null;
        // Load the file and deserialize the object
        try {
            FileInputStream fin = new FileInputStream("object.dat");
            ObjectInputStream ois = new ObjectInputStream(fin);
            s2 = (Sub) ois.readObject();
            ois.close();
        } catch (Exception e) {
            e.printStackTrace();
        }

        System.out.println( s2.toString() );
    }
}

قم بتشغيل الرئيسية في الفرعية مرة واحدة للحصول عليه لإنشاء وحفظ كائن. ثم قم بتغيير SERIALVERVERVERVERVERVERNUID في الفئة الأساسية، قم بتعليق الخطوط في الرئيسية التي تحفظ الكائن (لذلك لا يحفظها مرة أخرى، يمكنك فقط تحميل Old One)، وتشغيله مرة أخرى. هذا سيؤدي إلى استثناء

java.io.InvalidClassException: Base; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

نصائح أخرى

نعم، بشكل عام، لنفس السبب الذي يحتاجه أي فئة أخرى إلى معرف تسلسلي - لتجنب أن يتم إنشاؤه من أجله. في الأساس أي فئة (ليست واجهة) تنفذ Serializable يجب أن تحدد معرف الإصدار التسلسلي أو تقوم بإخطأ أخطاء عدم المخاطرة عند نفس. Class Compile ليس في الخادم والعميل JVMS.

هناك خيارات أخرى إذا كنت تحاول أن تفعل شيئا يتوهم. لست متأكدا مما تقصد به "إنه نية الفصول الفرعية ...". هل ستكتب أساليب التسلسل المخصصة (على سبيل المثال، readobject، readobject)؟ إذا كان الأمر كذلك هناك خيارات أخرى للتعامل مع فئة فائقة.

يرى:http://java.sun.com/javase/6/docs/api/java/io/serializable.html.

هث توم

في الواقع، مشيرا خارج رابط توم إذا فقد serialVersionID يتم حسابها فعلا بواسطة وقت تشغيل التسلسل، أي ليس خلال التجميع

إذا كانت الطبقة القابلة للتسلسل لا تعلن صراحة عن SerialVersionUID، فستحسب وقت تشغيل التسلسل قيمة Serialialuid افتراضية لهذه الفئة بناء على جوانب مختلفة من الفصل ...

هذا يجعل الأمور أكثر تعقيدا وجود إصدارات مختلفة من JRE.

من الناحية النظرية، تبدو البيانات المسلقة مثل هذا:

subClassData(className + version + fieldNames + fieldValues)
parentClassData(className + version + fieldNames + fieldValues)
... (up to the first parent, that implements Serializable)

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

إجابه: نعم، تحتاج إلى تقديم serialVersionUID في فئة مجردة القاعدة كذلك. حتى لو لم يكن لديه حقول (className + version يتم تخزينها حتى لو لم تكن هناك حقول).

لاحظ أيضا ما يلي:

  1. إذا لم يكن لدى الفصل حقلا، فقد تم العثور عليه في البيانات المتسلسلة (حقل إزالته)، يتم تجاهله.
  2. إذا كان للفئة حقلا، فلا يوجد في البيانات المتسلسلة (حقل جديد)، فهو يقع على 0 / False / Null (وليس إلى القيمة الافتراضية كما يتوقع المرء).
  3. إذا كان الحقل يغير نوع البيانات، يجب أن تكون القيمة الهجومية قابلة للتسليم للنوع الجديد. على سبيل المثال إذا كان لديك Object الحقل مع String قيمة، تغيير نوع الحقل إلى String سوف تنجح، ولكن التغيير إلى Integer متعود. ومع ذلك، تغيير الحقل من int ل long لن تعمل، على الرغم من أنه يمكنك تعيين int قيمة long عامل.
  4. إذا لم تعد الفئة الفرعية تمتد الفئة الأصل، والتي تمتد في البيانات المتسلسلة، يتم تجاهلها (كما هو الحال في الحالة 1).
  5. إذا كانت الفئة الفرعية تمتد الآن فئة، فلا يتم العثور عليها في البيانات المتسلسلة، فسيتم استعادة حقول الفئة الأصل مع قيمة 0 / FALSE / NULL (كما في حالة 2).

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

ملاحظة: إذا كانت الفئة الأساسية لا تنفذ Serializable وفوق الفئة الفرعية فقط، فسوف تتصرف الحقول من الفئة الأساسية transient.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top