سؤال

ما المقصود بـ "التسلسل الكائن"؟ هل يمكنك توضيح ذلك مع بعض الأمثلة؟

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

المحلول

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

نصائح أخرى

يمكنك التفكير في التسلسل كعملية لتحويل مثيل الكائن إلى تسلسل بايت (والذي قد يكون ثنائيًا أو لا يعتمد على التنفيذ).

إنه مفيد جدًا عندما تريد نقل بيانات كائن واحد عبر الشبكة ، على سبيل المثال من JVM إلى آخر.

في Java ، تم دمج آلية التسلسل في المنصة ، ولكن تحتاج إلى تنفيذ قابل للتسلسل واجهة لجعل كائن التسلسل.

يمكنك أيضًا منع بعض البيانات في كائنك من التسلسل عن طريق وضع علامة على السمة كـ عابر.

أخيرًا ، يمكنك تجاوز الآلية الافتراضية ، وتوفير خاص بك ؛ قد يكون هذا مناسبًا في بعض الحالات الخاصة. للقيام بذلك ، يمكنك استخدام واحد من الميزات الخفية في جافا.

من المهم أن نلاحظ أن ما يتم تسلسله هو "قيمة" الكائن ، أو المحتويات ، وليس تعريف الفئة. وبالتالي لا يتم تسلسل الأساليب.

فيما يلي عينة أساسية للغاية مع تعليقات لتسهيل قراءتها:

import java.io.*;
import java.util.*;

// This class implements "Serializable" to let the system know
// it's ok to do it. You as programmer are aware of that.
public class SerializationSample implements Serializable {

    // These attributes conform the "value" of the object.

    // These two will be serialized;
    private String aString = "The value of that string";
    private int    someInteger = 0;

    // But this won't since it is marked as transient.
    private transient List<File> unInterestingLongLongList;

    // Main method to test.
    public static void main( String [] args ) throws IOException  { 

        // Create a sample object, that contains the default values.
        SerializationSample instance = new SerializationSample();

        // The "ObjectOutputStream" class has the default 
        // definition to serialize an object.
        ObjectOutputStream oos = new ObjectOutputStream( 
                               // By using "FileOutputStream" we will 
                               // Write it to a File in the file system
                               // It could have been a Socket to another 
                               // machine, a database, an in memory array, etc.
                               new FileOutputStream(new File("o.ser")));

        // do the magic  
        oos.writeObject( instance );
        // close the writing.
        oos.close();
    }
}

عندما نقوم بتشغيل هذا البرنامج ، يتم إنشاء ملف "O.Ser" ويمكننا أن نرى ما حدث.

إذا قمنا بتغيير قيمة: SomeInteger على سبيل المثال integer.max_value, ، قد نقارن الإخراج لمعرفة الفرق.

إليك لقطة شاشة توضح هذا الاختلاف على وجه التحديد:

alt text

هل يمكنك تمييز الفروقات؟ ؛)

يوجد مجال إضافي ذي صلة في تسلسل Java: SerialVersionuid لكني أعتقد أن هذا وقت طويل جدًا لتغطيته.

جريئة للإجابة على سؤال عمره 6 سنوات ، مضيفًا فهمًا عالي المستوى للأشخاص الجدد في جافا

ما هو التسلسل؟

تحويل كائن إلى البايتات والبايت مرة أخرى إلى كائن (إلغاء التخلص).

متى يتم استخدام التسلسل؟

عندما نريد أن تستمر في الكائن. عندما نريد أن يوجد الكائن بعد عمر JVM.

مثال على العالم الحقيقي:

ATM: عندما يحاول حامل الحساب سحب الأموال من الخادم من خلال ATM ، سيتم تسلسل معلومات حامل الحساب مثل تفاصيل الانسحاب وإرسالها إلى الخادم حيث يتم إلغاء تفاصيل التفاصيل واستخدامها لأداء العمليات.

كيف يتم تنفيذ التسلسل في جافا.

  1. ينفذ java.io.Serializable واجهة (واجهة علامة لذلك لا توجد طريقة للتنفيذ).

  2. استمر في الكائن: استخدم java.io.ObjectOutputStream الفئة ، دفق مرشح وهو غلاف حول دفق بايت من المستوى الأدنى (لكتابة كائن إلى ملف أنظمة أو نقل كائن مسطح عبر سلك الشبكة وإعادة بنائه على الجانب الآخر).

    • writeObject(<<instance>>) - لكتابة كائن
    • readObject() - لقراءة كائن تسلسلي

تذكر:

عندما تقوم بتسلسل كائن ، سيتم حفظ حالة الكائن فقط ، وليس ملف فئة الكائن أو طرقه.

عندما تقوم بتسلسل كائن 2 بايت ، ترى ملف تسلسلي 51 بايت.

خطوات كيف يتم تسلسل الكائن وإزالة التخصيص.

الإجابة على: كيف تم تحويله إلى ملف 51 بايت؟

  • يكتب أولاً بيانات سحرية دفق التسلسل (Stream_Magic = "ac ed" و Stream_Version = إصدار JVM).
  • ثم يكتب البيانات الوصفية للفئة المرتبطة بمثيل (طول الفصل ، اسم الفصل ، SerialVersionuid).
  • ثم يكتب بشكل متكرر بيانات التعريف الفائقة حتى تجد java.lang.Object.
  • ثم يبدأ بالبيانات الفعلية المرتبطة بالمثال.
  • أخيرًا ، يكتب بيانات الكائنات المرتبطة بالمثال الذي يبدأ من البيانات الوصفية إلى المحتوى الفعلي.

إذا كنت مهتمًا بالمزيد في معلومات الإدارة حول تسلسل Java ، فيرجى التحقق من ذلك حلقة الوصل.

يحرر : واحد أكثر جيدة حلقة الوصل ليقرأ.

سيجيب هذا على بعض الأسئلة المتكررة:

  1. كيف لا تسلسل أي مجال في الفصل.
    الإجابة: استخدم الكلمة الرئيسية العابرة

  2. عندما يتم تسلسل فئة الطفل ، هل يتم تسلسل فئة الوالدين؟
    الإجابة: لا ، إذا كان الوالد لا يمتد مجال الواجهة القابلة للتسلسل ، فلا يتم تسلسل حقل الوالدين.

  3. عندما يتم تسلسل الوالد هل يتم تسلسل فئة الطفل؟
    الإجابة: نعم ، فئة الطفل الافتراضية أيضًا الحصول على تسلسل.

  4. كيف تتجنب الحصول على فئة الأطفال من التسلسل؟
    الإجابة: أ. تجاوز طريقة الكتابة والراحة ورمي NotSerializableException.

    ب. كما يمكنك وضع علامة على جميع الحقول عابرة في فئة الطفل.

  5. بعض الفئات على مستوى النظام مثل الخيط ، OutputStream والفئات الفرعية ، والمقبس غير قابلة للتسلسل.

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

أحببت الطريقة التي يقدمها @soScarryz. على الرغم من أنني هنا أستمر في قصة التسلسل الذي كتب في الأصل @amitgupta.

على الرغم من أن معرفة بنية فئة الروبوت والحصول على بيانات متسلسلة لم يتمكن عالم الأرض من تمييز البيانات التي يمكن أن تجعل الروبوتات تعمل.

Exception in thread "main" java.io.InvalidClassException:
SerializeMe; local class incompatible: stream classdesc
:

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

سنتان من مدونتي الخاصة:

هنا تفسير مفصل للتسلسل: (مدونتي الخاصة)

التسلسل:

التسلسل هو عملية استمرار حالة كائن. يتم تمثيله وتخزينه في شكل سلسلة من البايتات. يمكن تخزين هذا في ملف. تسمى عملية قراءة حالة الكائن من الملف واستعادتها.

ما هي حاجة التسلسل؟

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

مثال رمز وشرح:

أولاً ، دعونا نلقي نظرة على فئة العناصر:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

في الكود أعلاه يمكن رؤية ذلك العنصر أدوات الفصل قابل للتسلسل.

هذه هي الواجهة التي تمكن الفئة من التسلسل.

الآن يمكننا رؤية متغير يسمى SerialVersionuid تتم تهيئته إلى متغير طويل. يتم حساب هذا الرقم بواسطة برنامج التحويل البرمجي بناءً على حالة الفصل وسمات الفصل. هذا هو الرقم الذي سيساعد JVM على تحديد حالة كائن ما عندما يقرأ حالة الكائن من الملف.

لذلك يمكننا إلقاء نظرة على وثائق أوراكل الرسمية:

يرتبط وقت التشغيل التسلسلي مع كل إصدار إصدار من الفئة A القابل للتسلسل ، والذي يسمى تسلسليًا ، والذي يتم استخدامه أثناء التخلص من التحقق من أن المرسل والمستقبل للكائن المسلسل قد قاموا بتحميل فئات لهذا الكائن المتوافق فيما يتعلق بالتسلسل. إذا قام جهاز الاستقبال بتحميل فئة للكائن الذي يحتوي على serialversionuid مختلف عن فئة المرسل المقابلة ، فإن التخلص من التخلص سيؤدي إلى وجود غير صالح. يمكن للطبقة القابلة للتسلسل أن تعلن تصنيفها التسلسلي بشكل صريح من خلال إعلان حقل يسمى "SerialVersionuid" الذي يجب أن يكون ثابتًا ، نهائيًا ، ونوع طويل: أي مسلسل نهائي متسلسل طويل الأمد = 42L ؛ إذا لم تعلن الفئة القابلة للتسلسل بشكل صريح عن نسخ متسلسل ، فإن وقت تشغيل التسلسل سيحسب قيمة التسلسل التسلسلي لتلك الفئة القائمة على جوانب مختلفة من الفئة ، كما هو موضح في مواصفات كائن JAVA (TM). ومع ذلك ، يوصى بشدة أن تعلن جميع الفئات القابلة للتسلسل بشكل صريح القيم التسلسلية ، لأن حساب التسلسل الافتراضي حساس للغاية لتفاصيل الطبقة التي قد تختلف حسب تطبيقات البرمجيات ، وبالتالي يمكن أن تؤدي إلى عدم وجود غير متوقعة خلال التخلص من التسلسل. لذلك ، لضمان قيمة متسلسلة متسلسلة عبر تطبيقات برنامج التحويل البرمجي Java المختلفة ، يجب أن تعلن الفئة القابلة للتسلسل عن قيمة التسلسل التسلسلي الصريح. يُنصح بشدة أن تستخدم الإعلانات التسلسلية الصريحة المعدل الخاص حيثما أمكن ذلك ، حيث تنطبق هذه الإعلانات فقط على التصنيف الفوري-الحقول الإقلاعية غير المفيدة كأعضاء ورثين.

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

إذا لم يكن الحقل قابلًا للتسلسل ، فيجب وضع علامة عابرة. هنا وضعنا علامة itemCostPrice كما عابرة ولا تريد كتابتها في ملف

الآن دعونا نلقي نظرة على كيفية كتابة حالة كائن في الملف ثم نقرأها من هناك.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

في ما سبق يمكننا أن نرى مثالًا على التسلسل وإلغاء التسلسل للكائن.

لذلك استخدمنا فئتين. لتسلسل الكائن الذي استخدمناه ObjectOutputStream. لقد استخدمنا طريقة الكتابة لكتابة الكائن في الملف.

من أجل إلغاء التسلل ، استخدمنا ObjectInputStream الذي يقرأ من الكائن من الملف. يستخدم ReadObject لقراءة بيانات الكائن من الملف.

سيكون إخراج الكود أعلاه مثل:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

لاحظ أن itemCostPrice من الكائن المنحرف هو لا شيء لأنه لم يكتب.

لقد ناقشنا بالفعل أساسيات تسلسل Java في الجزء الأول من هذا المقال.

الآن دعونا نناقشها بعمق وكيف تعمل.

أولاً لنبدأ بـ SerialVersionuid.

ال SerialVersionuid يستخدم كعنصر تحكم الإصدار في فئة قابلة للتسلسل.

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

خوارزمية جافا لحساب SerialVersionuid (اقرأ المزيد من التفاصيل هنا)

  1. اسم الفصل.
    1. المعدلات الفئة المكتوبة على أنها عدد صحيح 32 بت.
    2. اسم كل واجهة مرتبة بالاسم.
    3. لكل حقل من الفئة المرتبة حسب اسم الحقل (باستثناء الحقول الثابتة والخاصة العابرة الخاصة: اسم الحقل. المعدلات للحقل المكتوبة كمكتسب 32 بت. واصف الحقل.
    4. في حالة وجود تهيئة الفصل ، اكتب ما يلي: اسم الطريقة ،.
    5. المعدل للطريقة ، java.lang.reflect.modier.static ، مكتوبة على أنها عدد صحيح 32 بت.
    6. واصف الطريقة ، () الخامس.
    7. لكل مُنشئ غير خاص تم فرزه بواسطة اسم الطريقة والتوقيع: اسم الطريقة ،. المعدلات للطريقة المكتوبة على أنها عدد صحيح 32 بت. واصف الطريقة.
    8. لكل طريقة غير خاصة تم فرزها حسب اسم الطريقة والتوقيع: اسم الطريقة. المعدلات للطريقة المكتوبة على أنها عدد صحيح 32 بت. واصف الطريقة.
    9. يتم تنفيذ خوارزمية SHA-1 على دفق البايتات التي تنتجها DataOutputStream وتنتج خمس قيم 32 بت SHA [0..4]. يتم تجميع قيمة التجزئة من قيم 32 بت من 32 بت من Digest Message SHA-1. إذا كانت نتيجة هضم الرسالة ، الكلمات الخمسة 32 بت H0 H1 H2 H3 H4 ، في مجموعة من خمس قيم int المسمى SHA ، سيتم حساب قيمة التجزئة على النحو التالي:
    long hash = ((sha[0] >>> 24) & 0xFF) |
>            ((sha[0] >>> 16) & 0xFF) << 8 |
>            ((sha[0] >>> 8) & 0xFF) << 16 |
>            ((sha[0] >>> 0) & 0xFF) << 24 |
>            ((sha[1] >>> 24) & 0xFF) << 32 |
>            ((sha[1] >>> 16) & 0xFF) << 40 |
>            ((sha[1] >>> 8) & 0xFF) << 48 |
>        ((sha[1] >>> 0) & 0xFF) << 56;

خوارزمية تسلسل جافا

يوصف الخوارزمية لتسلسل كائن على النحو التالي:
1. يكتب البيانات الوصفية للفئة المرتبطة بمثيل.
2. يكتب بشكل متكرر وصف الفئة الفائقة حتى تجد java.lang.Object.
3. بمجرد الانتهاء من كتابة معلومات البيانات الوصفية ، يبدأ بعد ذلك بالبيانات الفعلية المرتبطة بالمثال. ولكن هذه المرة ، يبدأ من الطبقة الفائقة الأعلى.
4. يكتب بشكل متكرر البيانات المرتبطة بالمثال ، بدءًا من أقل فئة فائقة إلى الفئة الأكثر مشاركة.

أشياء لتأخذها بالحسبان:

  1. لا يمكن تسلسل الحقول الثابتة في الفصل.

    public class A implements Serializable{
         String s;
         static String staticString = "I won't be serializable";
    }
    
  2. إذا كان SerialVersionuid مختلفًا في فئة القراءة ، فسوف يرمي أ InvalidClassException استثناء.

  3. إذا كان الفصل ينفذ قابلاً للتسلسل ، فستكون جميع فئاته الفرعية قابلة للتسلسل أيضًا.

    public class A implements Serializable {....};
    
    public class B extends A{...} //also Serializable
    
  4. إذا كان لدى الفصل مرجعًا لفئة أخرى ، فيجب أن تكون جميع المراجع قابلة للتسلسل وإلا فلن يتم تنفيذ عملية التسلسل. في مثل هذه الحالة ، notserializableException يتم إلقاؤه في وقت التشغيل.

على سبيل المثال:

public class B{
     String s,
     A a; // class A needs to be serializable i.e. it must implement Serializable
}

التسلسل يعني استمرار الأشياء في جافا. إذا كنت ترغب في حفظ حالة الكائن وتريد إعادة بناء الدولة لاحقًا (قد تكون في JVM أخرى) يمكن استخدام التسلسل.

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

على سبيل المثال:

ObjectInputStream oos = new ObjectInputStream(                                 
                                 new FileInputStream(  new File("o.ser")) ) ;
SerializationSample SS = (SearializationSample) oos.readObject();

القابلة للاتصال هي واجهة علامة تمثل أن صفك قابل للتسلسل. تعني واجهة العلامة أنها مجرد واجهة فارغة وأن استخدام تلك الواجهة سوف يخطر JVM بأن هذه الفئة يمكن أن تكون قابلة للتسلسل.

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

http://en.wikipedia.org/wiki/Serialization

التسلسل هو عملية حفظ كائن في وسيط تخزين (مثل ملف ، أو مخزن مؤقت للذاكرة) أو لإرساله عبر اتصال الشبكة في شكل ثنائي. الكائنات المسلسل هي JVM مستقلة ويمكن إعادة تخصيصها من قبل أي JVM. في هذه الحالة ، يتم تحويل حالة كائنات Java "في الذاكرة" إلى دفق بايت. لا يمكن فهم هذا النوع من الملف من قبل المستخدم. إنها أنواع خاصة من الكائن IE إعادة استخدامها بواسطة JVM (الجهاز الظاهري Java). وتسمى هذه العملية من تسلسل كائن أيضا انحراف أو تنظيم كائن.

يجب تنفيذ الكائن المسلسل java.io.Serializable واجهه المستخدم. تكتب آلية التسلسل الافتراضية لكائن فئة الكائن ، وتوقيع الفئة ، وقيم جميع الحقول غير المترتبة وغير المنتظمة.

class ObjectOutputStream extends java.io.OutputStream implements ObjectOutput,

ObjectOutput واجهة تمتد DataOutput واجهة ويضيف طرقًا لتسلسل الكائنات وكتابة بايت إلى الملف. ال ObjectOutputStream يمتد java.io.OutputStream وتنفذ ObjectOutput واجهه المستخدم. يقوم بتسلسل الكائنات والصفائف والقيم الأخرى إلى دفق. وبالتالي فإن مُنشئ ObjectOutputStream مكتوب على النحو التالي:

ObjectOutput ObjOut = new ObjectOutputStream(new FileOutputStream(f));

تم استخدام الرمز أعلاه لإنشاء مثيل ObjectOutput الفصل مع ObjectOutputStream( ) المُنشئ الذي يأخذ مثيل FileOuputStream كمعلمة.

ال ObjectOutput يتم استخدام الواجهة عن طريق تنفيذ ObjectOutputStream صف دراسي. ال ObjectOutputStream تم بناؤه لتسلسل الكائن.

إلغاء تخصيص كائن في جافا

تسمى العملية المعاكسة للتسلسل التسلسلي ، أي لاستخراج البيانات من سلسلة من البايتات المعروفة باسم التخلص من التضخيم التي تسمى أيضًا التضخيم أو غير الممتاز.

ObjectInputStream يمتد java.io.InputStream وتنفذ ObjectInput واجهه المستخدم. إنه يستحضر الكائنات والصفائف والقيم الأخرى من دفق الإدخال. وبالتالي فإن مُنشئ ObjectInputStream مكتوب على النحو التالي:

ObjectInputStream obj = new ObjectInputStream(new FileInputStream(f));

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

جافا التسلسل الكائن

enter image description here

Serialization هي آلية لتحويل رسم بياني لكائنات Java إلى مجموعة من البايتات للتخزين (to disk file) أو انتقال (across a network) ، ثم باستخدام هجر يمكننا استعادة الرسم البياني للكائنات. تتم استعادة الرسوم البيانية للكائنات بشكل صحيح باستخدام آلية مشاركة المرجع. ولكن قبل التخزين ، تحقق مما إذا كانت SerialVersionuid من ملف/شبكة الإدخال و .Class File SerialVersionuid هي نفسها. إذا لم يكن كذلك ، رمي أ java.io.InvalidClassException.

يجب أن تحدد كل فئة من فئة الإصدار إصدار الفئة الأصلي الذي يمكنه كتابة التدفقات التي يمكن أن تقرأ منها. على سبيل المثال ، يجب أن يعلن الفئة ذات الإصدار:

بناء الجملة SerialVersionuid

// ANY-ACCESS-MODIFIER static final long serialVersionUID = (64-bit has)L;
private static final long serialVersionUID = 3487495895819393L;

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

ملحوظة - يوصى بشدة أن تعلن جميع الطبقات القابلة للتسلسل صراحةً أن النقل التسلسلي ، since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, ، وبالتالي يمكن أن تؤدي إلى تعارضات تسلسلية غير متوقعة أثناء هروب التالي ، مما تسبب في فشل إلغاء التالي.

فحص الطبقات التسلسلية

enter image description here


كائن Java قابل للتسلسل فقط. إذا كان فئة أو أي من فطائره الفائقة تنفذ إما java.io.serializable واجهة أو واجهة فرعية ، java.io.externalizable.

  • يجب أن ينفذ الفصل java.io.serializable واجهة من أجل تسلسل هدفها بنجاح. Serializable هي واجهة علامة وتستخدم لإبلاغ المترجم بأن الفئة التي تنفذها يجب إضافتها إلى السلوك القابل للتسلسل. هنا Java Virtual Machine (JVM) مسؤولة عن التسلسل التلقائي.

    الكلمة الرئيسية العابرة: java.io.Serializable interface

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

    • يتم تجاهل الحقول المعلنة على أنها عابرة أو ثابتة من خلال عملية التسلسل.

    عابر & متطايره

    +--------------+--------+-------------------------------------+
    |  Flag Name   |  Value | Interpretation                      |
    +--------------+--------+-------------------------------------+
    | ACC_VOLATILE | 0x0040 | Declared volatile; cannot be cached.|
    +--------------+--------+-------------------------------------+
    |ACC_TRANSIENT | 0x0080 | Declared transient; not written or  |
    |              |        | read by a persistent object manager.|
    +--------------+--------+-------------------------------------+
    
    class Employee implements Serializable {
        private static final long serialVersionUID = 2L;
        static int id;
    
        int eno; 
        String name;
        transient String password; // Using transient keyword means its not going to be Serialized.
    }
    
  • يتيح تنفيذ الواجهة الخارجية للكائن تولي التحكم الكامل على محتويات وتنسيق النموذج التسلسلي للكائن. يتم استدعاء طرق الواجهة الخارجية القابلة للاتصالات ، والكتابة على نطاق واسع ، وقراءة ، لإنقاذ حالة الكائنات واستعادتها. عند تنفيذها بواسطة فئة ، يمكنهم كتابة وقراءة حالتهم الخاصة باستخدام جميع أساليب ObjectOutput و ObjectInput. تقع على عاتق الكائنات مسؤولية التعامل مع أي إصدار يحدث.

    class Emp implements Externalizable {
        int eno; 
        String name;
        transient String password; // No use of transient, we need to take care of write and read.
    
        @Override
        public void writeExternal(ObjectOutput out) throws IOException {
            out.writeInt(eno);
            out.writeUTF(name);
            //out.writeUTF(password);
        }
        @Override
        public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
            this.eno = in.readInt();
            this.name = in.readUTF();
            //this.password = in.readUTF(); // java.io.EOFException
        }
    }
    
  • فقط الكائنات التي تدعم الواجهة java.io.serializable أو java.io.externalizable يمكن أن تكون written to/read from تيارات. يتم تشفير فئة كل كائن قابل للتسلسل بما في ذلك اسم الفئة وتوقيع الفئة ، وقيم حقول الكائن والمصفوفات ، وإغلاق أي كائنات أخرى مشار إليها من الكائنات الأولية.

مثال متسلسل للملفات

public class SerializationDemo {
    static String fileName = "D:/serializable_file.ser";

    public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException {
        Employee emp = new Employee( );
        Employee.id = 1; // Can not Serialize Class data.
        emp.eno = 77;
        emp.name = "Yash";
        emp.password = "confidential";
        objects_WriteRead(emp, fileName);

        Emp e = new Emp( );
        e.eno = 77;
        e.name = "Yash";
        e.password = "confidential";
        objects_WriteRead_External(e, fileName);

        /*String stubHost = "127.0.0.1";
        Integer anyFreePort = 7777;
        socketRead(anyFreePort); //Thread1
        socketWrite(emp, stubHost, anyFreePort); //Thread2*/

    }
    public static void objects_WriteRead( Employee obj, String serFilename ) throws IOException{
        FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );
        objectOut.writeObject( obj );
        objectOut.close();
        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            FileInputStream fis = new FileInputStream( new File( serFilename ) );
            ObjectInputStream ois = new ObjectInputStream( fis );
            Object readObject;
            readObject = ois.readObject();
            String calssName = readObject.getClass().getName();
            System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException

            Employee emp = (Employee) readObject;
            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    public static void objects_WriteRead_External( Emp obj, String serFilename ) throws IOException {
        FileOutputStream fos = new FileOutputStream(new File( serFilename ));
        ObjectOutputStream objectOut = new ObjectOutputStream( fos );

        obj.writeExternal( objectOut );
        objectOut.flush();

        fos.close();

        System.out.println("Data Stored in to a file");

        try {
            // create a new instance and read the assign the contents from stream.
            Emp emp = new Emp();

            FileInputStream fis = new FileInputStream(new File( serFilename ));
            ObjectInputStream ois = new ObjectInputStream( fis );

            emp.readExternal(ois);

            System.out.format("Obj[No:%s, Name:%s, Pass:%s]", emp.eno, emp.name, emp.password);

            ois.close();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

مثال قابل للتسلسل على الشبكة

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

/**
 * Creates a stream socket and connects it to the specified port number on the named host. 
 */
public static void socketWrite(Employee objectToSend, String stubHost, Integer anyFreePort) {
    try { // CLIENT - Stub[marshalling]
        Socket client = new Socket(stubHost, anyFreePort);
        ObjectOutputStream out = new ObjectOutputStream(client.getOutputStream());
        out.writeObject(objectToSend);
        out.flush();
        client.close();
    } catch (IOException e) {
        e.printStackTrace();
    }
}
// Creates a server socket, bound to the specified port. 
public static void socketRead(  Integer anyFreePort ) {
    try { // SERVER - Stub[unmarshalling ]
        ServerSocket serverSocket = new ServerSocket( anyFreePort );
        System.out.println("Server serves on port and waiting for a client to communicate");
            /*System.in.read();
            System.in.read();*/

        Socket socket = serverSocket.accept();
        System.out.println("Client request to communicate on port server accepts it.");

        ObjectInputStream in = new ObjectInputStream(socket.getInputStream());
        Employee objectReceived = (Employee) in.readObject();
        System.out.println("Server Obj : "+ objectReceived.name );

        socket.close();
        serverSocket.close();
    } catch (IOException | ClassNotFoundException e) {
        e.printStackTrace();
    }
}

@نرى

التسلسل هو عملية تحويل كائن Java إلى صفيف بايت ثم العودة إلى كائن مرة أخرى مع حالته المحفوظة. مفيد لأشياء مختلفة مثل إرسال الكائنات عبر الشبكة أو التخزين المؤقت للأشياء إلى القرص.

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

إرجاع الملف ككائن: http://www.tutorialspoint.com/java/java_serialization.htm

        import java.io.*;

        public class SerializeDemo
        {
           public static void main(String [] args)
           {
              Employee e = new Employee();
              e.name = "Reyan Ali";
              e.address = "Phokka Kuan, Ambehta Peer";
              e.SSN = 11122333;
              e.number = 101;

              try
              {
                 FileOutputStream fileOut =
                 new FileOutputStream("/tmp/employee.ser");
                 ObjectOutputStream out = new ObjectOutputStream(fileOut);
                 out.writeObject(e);
                 out.close();
                 fileOut.close();
                 System.out.printf("Serialized data is saved in /tmp/employee.ser");
              }catch(IOException i)
              {
                  i.printStackTrace();
              }
           }
        }

    import java.io.*;
    public class DeserializeDemo
    {
       public static void main(String [] args)
       {
          Employee e = null;
          try
          {
             FileInputStream fileIn = new FileInputStream("/tmp/employee.ser");
             ObjectInputStream in = new ObjectInputStream(fileIn);
             e = (Employee) in.readObject();
             in.close();
             fileIn.close();
          }catch(IOException i)
          {
             i.printStackTrace();
             return;
          }catch(ClassNotFoundException c)
          {
             System.out.println("Employee class not found");
             c.printStackTrace();
             return;
          }
          System.out.println("Deserialized Employee...");
          System.out.println("Name: " + e.name);
          System.out.println("Address: " + e.address);
          System.out.println("SSN: " + e.SSN);
          System.out.println("Number: " + e.number);
        }
    }

|* تسلسل فئة: تحويل كائن إلى بايت وبيوت إلى الكائن (إزالة الإرهاق).

class NamCls implements Serializable
{
    int NumVar;
    String NamVar;
}

| => تخصيص الكائن هو عملية تحويل حالة كائن إلى بخار بايت.

  • |-> تنفيذ عندما تريد أن يكون الكائن موجودًا إلى ما بعد عمر JVM.
  • |-> يمكن تخزين الكائن المسلسل في قاعدة البيانات.
  • |-> لا يمكن قراءة الكائنات القابلة للتسلسل وفهمها من قبل البشر حتى نتمكن من تحقيق الأمن.

| => تخصيص الكائن هو عملية الحصول على حالة كائن وتخزينها في كائن (java.lang.object).

  • |-> قبل تخزين حالتها ، يتحقق ما إذا كانت النموذج المسلسل/شبكة الإدخال/الشبكة.
    إن لم يكن رمي java.io.invalidclassexception.

| => كائن Java قابل للتسلسل فقط ، إذا كان فئته أو أي من فطائره الفائقة

  • ينفذ إما الواجهة java.io.serializable أو
  • واجهة الفرعية ، java.io.externalizable.

| => لا يمكن تسلسل الحقول الثابتة في الفصل.

class NamCls implements Serializable
{
    int NumVar;
    static String NamVar = "I won't be serializable";;
}

| => إذا كنت لا ترغب في تسلسل متغير فئة استخدم الكلمة الرئيسية العابرة

class NamCls implements Serializable
{
    int NumVar;
    transient String NamVar;
}

| => إذا كان الفصل ينفذ قابلاً للتسلسل ، فستكون جميع فئاته الفرعية قابلة للتسلسل أيضًا.

| => إذا كان لدى الفصل مرجع لفئة أخرى ، فلن يتم إجراء جميع المراجع التسلسلية وإلا فلن يتم تنفيذ عملية التسلسل. في مثل هذه الحالة ،
يتم إلقاء NotSerializableException في وقت التشغيل.

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