تسلسل الكائنات في Java: دليل شامل مع أمثلة

مدرب بايثون أونلاين للمبتدئين

تعلم Python بسهولة دون إرهاق نظري. حل مهام عملية مع التحقق التلقائي واكتب الكود مباشرة في المتصفح.

ابدأ الدورة

تسلسل الكائنات في Java: من الأساسيات إلى التقنيات المتقدمة

\n\n

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

\n\n

الأساسيات: واجهة Serializable

\n\n

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

\n\n
import java.io.Serializable;\n\npublic class User implements Serializable {\n    private static final long serialVersionUID = 1L;\n    private String name;\n    private int age;\n\n    public User(String name, int age) {\n        this.name = name;\n        this.age = age;\n    }\n\n    @Override\n    public String toString() {\n        return "User{name='" + name + "', age=" + age + "}";\n    }\n}
\n\n

الحقل serialVersionUID هو معرف فريد لإصدار الفئة. إذا لم يتم تعريفه بشكل صريح، فستقوم JVM بحسابه تلقائيًا، ولكن هذا قد يؤدي إلى InvalidClassException عند إلغاء التسلسل إذا تغيرت الفئة. يُوصى دائمًا بتعيينه يدويًا.

\n\n

عملية التسلسل وإلغاء التسلسل

\n\n

لكتابة كائن إلى تيار، يُستخدم ObjectOutputStream، وللقراءة يُستخدم ObjectInputStream. لنلق نظرة على مثال أساسي:

\n\n
import java.io.*;\n\npublic class SerializationDemo {\n    public static void main(String[] args) {\n        User user = new User("أليكسي", 30);\n\n        // التسلسل\n        try (FileOutputStream fos = new FileOutputStream("user.ser");\n             ObjectOutputStream oos = new ObjectOutputStream(fos)) {\n            oos.writeObject(user);\n            System.out.println("تم تسلسل الكائن: " + user);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        // إلغاء التسلسل\n        try (FileInputStream fis = new FileInputStream("user.ser");\n             ObjectInputStream ois = new ObjectInputStream(fis)) {\n            User restoredUser = (User) ois.readObject();\n            System.out.println("تم استعادة الكائن: " + restoredUser);\n        } catch (IOException | ClassNotFoundException e) {\n            e.printStackTrace();\n        }\n    }\n}
\n\n

عند إلغاء التسلسل، لا يتم استدعاء مُنشئ الكائن — يتم استعادة الحالة مباشرة من التيار. هذا فرق مهم عن إنشاء الكائن العادي باستخدام new.

\n\n

الكلمة المفتاحية transient

\n\n

أحيانًا يكون من الضروري استبعاد بعض الحقول من التسلسل، مثل كلمات المرور أو الحسابات المؤقتة. لهذا، يُستخدم المُعدِّل transient. الحقول المميزة به تحصل على القيم الافتراضية (0، null، false) عند التسلسل.

\n\n
public class UserWithPassword implements Serializable {\n    private static final long serialVersionUID = 1L;\n    private String login;\n    private transient String password; // لن يتم تسلسله\n\n    public UserWithPassword(String login, String password) {\n        this.login = login;\n        this.password = password;\n    }\n\n    @Override\n    public String toString() {\n        return "User{login='" + login + "', password='" + password + "'}";\n    }\n}
\n\n

بعد إلغاء التسلسل، سيكون الحقل password بقيمة null. هذا مناسب للأمان، ولكنه يتطلب منطقًا إضافيًا للاستعادة.

\n\n

التسلسل المخصص: طريقتي writeObject و readObject

\n\n

إذا كان السلوك القياسي غير مناسب، يمكن إعادة تعريف الطرق الخاصة

توصيات