التسلسل المخصص: writeObject وreadObject
تجاوز writeObject وreadObject لتنفيذ التشفير أو الضغط أو معالجة الحقول المخصصة
التسلسل المخصص: writeObject وreadObject درس مجاني في Java Academy على CoddyKit. هذا هو الدرس 3 من أصل 4. يمكنك قراءة الدرس كاملاً أدناه مجاناً — ثم تمرن عليه مباشرة في المتصفح باستخدام محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7. هذا الدرس جزء من مسار التعلم في Java Academy، وتقدمك يتزامن عبر الويب وتطبيق CoddyKit. تتضمن دورة Java Academy 4 دروس في المجموع.
متى لا يكفي التسلسل الافتراضي؟
يحفظ التسلسل الافتراضي جميع الحقول غير المعلّمة بـ transient كما هي. لكنكم قد تحتاجون أحيانًا إلى التشفير أو الضغط أو تمثيل مختلف. وهنا يأتي دور خطافي writeObject وreadObject.
التصريح بـ writeObject
أضيفوا دالة private void writeObject(ObjectOutputStream oos). تستدعيها Java بدلًا من الآلية الافتراضية، فتتحكمون بدقة في ما تتم كتابته.
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject(); // write non-transient fields normally
oos.writeUTF(encrypt(this.secret)); // write encrypted secret
}التصريح بـ readObject
أضيفوا دالة private void readObject(ObjectInputStream ois). تستدعيها Java أثناء إلغاء التسلسل، وعليكم القراءة بالترتيب نفسه تمامًا الذي استخدمتموه في الكتابة.
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject(); // restore non-transient fields
this.secret = decrypt(ois.readUTF()); // decrypt and restore
}الترتيب مهم
كل ما تكتبونه في writeObject يجب أن تتم قراءته مجددًا بالترتيب نفسه في readObject. ويؤدي اختلاف الترتيب إلى StreamCorruptedException.
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.writeInt(version);
oos.writeUTF(data);
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
this.version = ois.readInt(); // same order
this.data = ois.readUTF();
}ضغط البيانات أثناء التسلسل
غلّفوا الدفق بـ GZIPOutputStream داخل writeObject لضغط الحقول الكبيرة، ثم استخدموا GZIPInputStream داخل readObject لفك الضغط.
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
try (GZIPOutputStream gz = new GZIPOutputStream(bos)) {
gz.write(largePayload.getBytes());
}
oos.writeObject(bos.toByteArray());
}خطاف readResolve
يُستدعى readResolve() بعد إلغاء التسلسل. أعيدوا كائنًا بديلًا، فهذا مفيد للـ Singleton والـ enum لضمان وجود نسخة واحدة فقط بعد إلغاء التسلسل.
public class AppConfig implements Serializable {
private static final AppConfig INSTANCE = new AppConfig();
private AppConfig() {}
public static AppConfig getInstance() { return INSTANCE; }
private Object readResolve() { return INSTANCE; } // return singleton
}خطاف writeReplace
يُستدعى writeReplace() قبل التسلسل. أعيدوا كائنًا مختلفًا ليتم تسلسله بدلًا من الكائن الأصلي؛ وهذا مفيد لأنماط الوكيل وبدائل التسلسل.
private Object writeReplace() {
return new UserProxy(this.id); // serialize a lightweight proxy
}التحقق من الحقول في readObject
يمكنكم إضافة منطق للتحقق داخل readObject لرفض البيانات غير الصالحة أو التي عُبث بها، باعتباره جزءًا من استراتيجية دفاع متعددة الطبقات.
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
if (age < 0 || age > 150) {
throw new InvalidObjectException("Invalid age: " + age);
}
}التعامل مع تغيّرات الإصدارات
استخدموا حقل إصدار في writeObject حتى يتمكن readObject من التعامل بسلاسة مع التنسيقات القديمة والجديدة أثناء عمليات الترحيل.
private static final int SERIAL_VERSION = 2;
private void writeObject(ObjectOutputStream oos) throws IOException {
oos.defaultWriteObject();
oos.writeInt(SERIAL_VERSION);
if (SERIAL_VERSION >= 2) oos.writeUTF(email); // new field
}
private void readObject(ObjectInputStream ois)
throws IOException, ClassNotFoundException {
ois.defaultReadObject();
int v = ois.readInt();
if (v >= 2) this.email = ois.readUTF();
}نمط وكيل التسلسل
منهج متين هو كتابة فئة داخلية خاصة وثابتة تلتقط الحد الأدنى من الحالة، ثم استخدام writeReplace لكتابة الوكيل، واستخدام readResolve فيه لإعادة إنشاء الكائن الأصلي.
اعتبارات الأداء
يضيف التسلسل المخصص كلفة استدعاء دوال، لكنه قد يقلل حجم الحمولة بشكل ملحوظ. أجروا قياسًا للأداء قبل التحسين، واستخدموا Externalizable عند الحاجة إلى أقصى قدر من التحكم.
اختبار سريع
ما الشرط الذي يجب أن يتحقق بشأن الترتيب في writeObject وreadObject؟
مراجعة
استبدلوا writeObject وreadObject للتعامل مع التشفير أو الضغط أو التنسيقات المخصصة. استخدموا readResolve مع Singleton. واقرؤوا دائمًا بالترتيب نفسه الذي تكتبون به.
تعلم Java مع معلم ذكاء اصطناعي — مجانًا
اكتب وقم بتشغيل أكوادك الفعلية في المتصفح، واحصل على مساعدة فورية من معلم ذكاء اصطناعي متاح 24/7، واستمر من حيث توقفت على الويب أو في التطبيق.
- الدورات
- 104
- الدروس
- 374
الأسئلة الشائعة
هل درس «التسلسل المخصص: writeObject وreadObject» مجاني؟
نعم — نص درس «التسلسل المخصص: writeObject وreadObject» كامل متاح مجاناً هنا على الويب. لتمرينه بشكل تفاعلي (محرر أكواد مدمج ومدرس ذكاء اصطناعي متاح 24/7) وفتح باقي دورة Java Academy، انتقل إلى CoddyKit PRO. تتضمن دورة Java Academy 4 دروس في المجموع.
ماذا ستتعلم في «التسلسل المخصص: writeObject وreadObject»؟
تجاوز writeObject وreadObject لتنفيذ التشفير أو الضغط أو معالجة الحقول المخصصة تتمرن على Java Academy مع أكواد عملية تشغلها مباشرة في المتصفح، ومدرس ذكاء اصطناعي متاح 24/7 يجيب على أسئلتك أثناء عملك.
هل أحتاج إلى خبرة سابقة لأبدأ Java Academy؟
لا تُشترط خبرة سابقة. Java Academy على CoddyKit منظم للمبتدئين حتى المتقدمين، لذا يمكنك البدء من هنا أو من البداية والتقدم بسرعتك الخاصة. هذا هو الدرس 3 من أصل 4.
كم من الوقت يستغرق درس «التسلسل المخصص: writeObject وreadObject»؟
معظم دروس CoddyKit تستغرق حوالي 5–10 دقائق. كل منها موجز وتفاعلي، لذا تحرز تقدماً مستمراً وتستأنف من حيث توقفت عبر الويب والتطبيق.
هل يمكنني كتابة وتشغيل أكواد في درس Java Academy هذا؟
نعم. كل درس في Java Academy يتضمن محرر أكواد مدمج، لذا تكتب وتشغل أكواداً حقيقية مباشرة في متصفحك وتحصل على تعليقات فورية من الذكاء الاصطناعي — بدون إعداد محلي.
جميع الدروس في هذه الدورة
- أساسيات تسلسل Java
- الحقول transient وserialVersionUID
- التسلسل المخصص: writeObject وreadObject
- البدائل الحديثة: JSON وProtocol Buffers