دالة clone()
جزء من قسم Object Oriented Programming في رحلة Java على Coddy — الدرس 43 من 87.
تنشئ الطريقة clone() نسخة من كائن. لاستخدامها، يجب أن تقوم فئتك بتنفيذ واجهة Cloneable وإعادة تعريف الطريقة clone() من فئة Object.
public class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}الآن يمكنك إنشاء نسخ مستقلة من الكائنات:
Person original = new Person("Alice", 25);
Person copy = original.clone();
// copy هو كائن منفصل بنفس القيمبشكل افتراضي، تقوم clone() بإجراء نسخ سطحي (shallow copy)، مما يعني أنها تنسخ القيم الأولية والمراجع. إذا كان الكائن الخاص بك يحتوي على كائنات أخرى كحقول، فسيشير كل من الكائن الأصلي والنسخة إلى نفس الكائنات المتداخلة. للحصول على نسخ مستقلة تماماً مع كائنات متداخلة، تحتاج إلى تنفيذ نسخ عميق (deep copy) عن طريق استنساخ تلك الكائنات المتداخلة أيضاً داخل طريقة clone() الخاصة بك.
التحدي
سهللنقم ببناء نظام إدارة مستندات يوضح عملية استنساخ الكائنات (object cloning). ستقوم بإنشاء فئة Document يمكن استنساخها لإنشاء نسخ مستقلة، مما يسمح للمستخدمين بتكرار المستندات مع الحفاظ على المستند الأصلي كما هو.
ستقوم بتنظيم الكود الخاص بك عبر ملفين:
Document.java: قم بإنشاء فئة تمثل مستنداً يدعم الاستنساخ. يحتوي المستند (Document) على ثلاثة حقول خاصة (private):title(String)، وauthor(String)، وversion(int). قم بتضمين منشئ (constructor) لتهيئة جميع الحقول وطرق جلب (getter methods) لكل منها. أضف أيضاً طريقةsetVersion(int version)لتحديث رقم الإصدار.اجعل فئة Document الخاصة بك تنفذ واجهة
Cloneableوقم بإعادة تعريف (override) طريقةclone()لإرجاعDocument. قم بمعالجةCloneNotSupportedExceptionداخل الطريقة عن طريق تغليفها فيRuntimeException.قم بإعادة تعريف
toString()لإرجاع:Document[title=X, author=Y, version=Z]حيث X و Y و Z هي قيم الحقول الفعلية.Main.java: قم بتفعيل فئة Document الخاصة بك عن طريق إنشاء مستند واستنساخه. ستتلقى ثلاثة مدخلات: العنوان (String)، والمؤلف (String)، ورقم الإصدار (int).قم بإنشاء مستند أصلي بهذه القيم، ثم استنسخه لإنشاء نسخة. بعد الاستنساخ، قم بتعديل إصدار النسخة عن طريق زيادته بمقدار 1 باستخدام
setVersion(). يوضح هذا أن النسخة المستنسخة مستقلة تماماً عن الأصل.اطبع ثلاثة أسطر:
Original:متبوعاً بـ toString() للمستند الأصليClone:متبوعاً بـ toString() للمستند المستنسخIndependent:متبوعاً بـtrueأوfalseللإشارة إلى ما إذا كان الأصل والنسخة كائنين مختلفين (استخدم مقارنة!=)
ستتلقى ثلاثة مدخلات: عنوان المستند (String)، واسم المؤلف (String)، ورقم الإصدار (int).
لاحظ كيف أنه بعد تعديل إصدار النسخة المستنسخة، يظل المستند الأصلي دون تغيير - وهذا يثبت أن clone() أنشأت نسخة مستقلة حقاً!
ورقة مرجعية
تنشئ الطريقة clone() نسخة من كائن ما. لاستخدامها، يجب أن تنفذ فئتك واجهة Cloneable وتقوم بإعادة تعريف الطريقة clone() من فئة Object:
public class Person implements Cloneable {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}إنشاء نسخ مستقلة:
Person original = new Person("Alice", 25);
Person copy = original.clone();
// copy هو كائن منفصل بنفس القيمبشكل افتراضي، تقوم clone() بإجراء نسخ سطحي (shallow copy)، حيث تنسخ القيم الأولية والمراجع. إذا كان كائنك يحتوي على كائنات أخرى كحقول، فسيشير كل من الأصل والنسخة إلى نفس الكائنات المتداخلة. للحصول على نسخ مستقلة حقاً مع الكائنات المتداخلة، قم بتنفيذ نسخ عميق (deep copy) عن طريق استنساخ تلك الكائنات المتداخلة أيضاً داخل طريقة clone() الخاصة بك.
جرّب بنفسك
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// قراءة المدخلات
String title = scanner.nextLine();
String author = scanner.nextLine();
int version = scanner.nextInt();
// TODO: إنشاء مستند أصلي (Document) بالقيم المدخلة
// TODO: استنساخ المستند الأصلي لإنشاء نسخة
// TODO: تعديل إصدار النسخة المستنسخة بزيادته بمقدار 1
// TODO: طباعة "Original: " متبوعاً بالمستند الأصلي
// TODO: طباعة "Clone: " متبوعاً بالمستند المستنسخ
// TODO: طباعة "Independent: " متبوعاً بـ true/false (التحقق مما إذا كان الأصل != النسخة)
}
}يتضمن هذا الدرس اختبارًا قصيرًا. ابدأ الدرس للإجابة عليه وتتبّع تقدمك.
جميع دروس Object Oriented Programming
1أساسيات الـ OOP
الملفات الخارجيةمقدمة في الـ OOPالفئات (Classes) مقابل الكائنات (Objects)الكلمة المفتاحية thisالدوال (Methods)الحقول (Attributes)دالة البناء (Constructor)تعدد أشكال دالة البناء (Constructor Overloading)مراجعة - آلة حاسبة بسيطة4الوراثة
الوراثة الأساسية (extends)الكلمة المفتاحية superإعادة تعريف الدوال (@Override)تسلسل المنشئات (Constructor Chaining)كلاس Objectالوراثة الأحادية ومتعددة المستوياتلماذا لا توجد وراثة متعددة للكلاساتمراجعة - هيكلية الموظفين7الدوال الخاصة وفئة Object
دالة toString()equals() و hashCode()دالة clone()compareTo() و Comparableواجهة Comparatorمراجعة - الترتيب المخصص2محددات الوصول والتغليف
نظرة عامة على مستويات الوصولدوال Getter و Setterإخفاء البياناتالكلمة المفتاحية finalمراجعة - مدير الحساب البنكي5تعدد الأشكال (Polymorphism)
أساسيات الـ Method Overloadingالـ Method Overriding (في وقت التشغيل)الـ Upcasting والـ Downcastingمعامل الـ instanceofالفئات والدوال المجردة (Abstract)مراجعة - حاسبة الأشكال8مفاهيم OOP المتقدمة
الـ Composition مقابل الـ Inheritanceالـ Aggregation مقابل الـ Compositionالفئات الداخلية والمتداخلة والمجهولة (Inner, Nested & Anonymous)الـ Enums ودوالهاالـ Records (Java 16+)الـ Sealed Classes (Java 17+)11أنماط التصميم - الجزء الأول
مقدمة في أنماط التصميمنمط Singletonنمط Factoryنمط Builderنمط Observerنمط Strategy3خصائص الفئة والعضو الساكن
المتغيرات الخاصة بالكائن مقابل المتغيرات الساكنةالدوال الساكنةالكتل البرمجية الساكنةالثوابت (static final)ملخص - العداد والأدوات المساعدة6الواجهات (Interfaces) والأصناف المجردة (Abstract Classes)
مقدمة في الواجهات (Interfaces)تنفيذ الواجهات (Interfaces)تنفيذ واجهات متعددةالـ Default و Static في الواجهاتالأصناف المجردة مقابل الواجهاتالواجهات الوظيفية (Functional Interfaces)مراجعة - نظام الدفع9الأنواع العامة (Generics)
مقدمة في الأنواع العامةالأصناف العامة (Generic Classes)الدوال العامة (Generic Methods)معاملات الأنواع المقيدةالرموز البديلة (?, extends, super)مراجعة - الحاويات العامة12أنماط التصميم - الجزء الثاني
نمط الأمرنمط المحولنمط المزيننمط طريقة القالبنمط الحالةنمط التركيبنمط المكرر