متى يكون من المنطقي أن يكون كائن جافا قابلاً للتسلسل ولكنه غير قابل للاستنساخ؟

StackOverflow https://stackoverflow.com/questions/2128216

سؤال

إذا قام فئة Java بتنفيذ Serializable واجهة ولكن ليس لديها جمهور clone() الطريقة ، عادة ما يكون من الممكن إنشاء نسخة عميقة مثل هذه:

class CloneHelper {
    @SuppressWarnings("unchecked")
    public static <T extends Serializable> T clone(T obj) {
        try {
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(baos);
            oos.writeObject(obj);
            oos.close();
            byte[] bytes = baos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(bytes);
            ObjectInputStream ois = new ObjectInputStream(bais);
            T copy = (T) ois.readObject();
            ois.close();
            return copy;
        } catch (ClassNotFoundException ex) {
            // Shouldn't happen
            throw new Error(ex);
        } catch (IOException ex) {
            // Probably a bug in T's custom serialization methods
            throw new RuntimeException(ex);
        }
    }
}

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

وإذا لم يكن استخدام هذه التقنية آمنًا ، فربما لا ينبغي الإعلان عن الفصل Serializable.

إذن ما أود معرفته هو ، إذا كان صفك Serializable, ، ما الذي قد يمنعك من تحديد الجمهور clone() الطريقة (باستخدام إما Cloneable واجهة أو منشئ نسخ؟)


متعلق ب: انسخ كائن في جافا

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

المحلول

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

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

بشكل منفصل ، لست متأكدًا من استنساخ () "مكسور" بقدر ما يصعب التنفيذ بشكل صحيح. مُنشئ النسخ أكثر طبيعية للاستخدام والحصول على IMHO الصحيح.

نصائح أخرى

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

نلاحظ أن Cloneable تعتبر الطريقة على نطاق واسع الآن مكسورة. يرى هذه المقالة مع Joshua Bloch لمزيد من المعلومات. على وجه الخصوص ليس لديها ملف clone() طريقة!

تعتبر Brian's Point About Clonable جيدة جدًا ، ولكن حتى لو عملت بشكل صحيح ، فلا تزال هناك حالات قد ترغب في أن تكون كائنًا قابلاً للتسلسل ولكن غير قابل للاستنساخ.

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

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

واحدة من أكبر المشكلات في التسلسل هي أنه لا يمكن جعلها غير قابلة للتغيير بسهولة. يجبرك التسلسل على تقديم حل وسط هنا.

سأكون مغرًا بإنشاء منشئات نسخ أسفل الرسم البياني للكائن. انها مجرد عمل أكثر جرومة للقيام به.

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

مرة أخرى ، حالات الحافة ، ولكن شيء تريد الانتباه إليه.

لقد فكرت للتو في حالة أخرى - عندما تكون التعداد.

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

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