إتقان استخدام يساوي من خلال الأمثلة التالية
package cn.galc.test;public class TestEquals { public static void main(String[] args) { /** * هنا يتم استخدام طريقة البناء Cat() لإنشاء قطتين جديدتين في ذاكرة الكومة اللون والوزن والارتفاع كلها متماثلة، ولكن c1 وc2 لن يكونا متساويين أبدًا، وذلك لأن c1 وc2 كائنان مرجعيان للقطتين في ذاكرة الكومة، * يحتوي على العناوين التي يمكن العثور على القطتين فيها، ولكن نظرًا لأنه يتم تخزين القطتين في مساحتين مختلفتين في ذاكرة الكومة، * يحتوي c1 وc2 على عنوانين مختلفين، لذلك لن يكون c1 وc2 متساويين أبدًا. */ Cat c1 = new Cat(1, 1, 1); Cat c2 = new Cat(1, 1, 1); System.out.println("نتيجة c1==c2 هي:"+(c1== c2 ));//false System.out.println("نتيجة c1.equals(c2) هي:"+c1.equals(c2));//false }}class Cat { int color, الوزن والارتفاع؛ارسم مخطط تحليل الذاكرة لتحليل نتائج المقارنة بين c1 وc2
برنامج:
القطة c1 = القطة الجديدة(1,1,1);القط c2 = القطة الجديدة(1,1,1);
بعد التنفيذ، يكون التخطيط في الذاكرة كما هو موضح أدناه:
يشير c1 إلى كائن، ويشير c2 أيضًا إلى كائن، ويحتوي C1 وc2 على العناوين المخزنة في ذاكرة الكومة لكائني Cat هذين بالتأكيد ليسا متساويين، وبالتالي فإن الجسمين المرجعيين c1 وc2 ليسا متساويين بالتأكيد. لذلك، إذا قمت بتنفيذ: "System.out.println(c1==c2);" ستكون النتيجة المطبوعة خاطئة بالتأكيد. لذا، يمكنك إنشاء كائنين جديدين. لا تقلق، لن تكون مراجع الكائنين متماثلة أبدًا، إذا كانا متماثلين، فسيتم الكتابة فوق أحدهما. ما إذا كان c1 يساوي c2 يقارن المحتوى الموجود في المرجعين c1 و c2، لأن مرجعي الكائنين اللذين تم إنتاجهما بواسطة new ليسا متماثلين أبدًا، لذا فإن محتويات المرجعين c1 و c2 ليست متماثلة أبدًا لا يمكن لـ c1 أن يساوي c2 أبدًا. لذلك، فإن المقارنة بين مرجعي كائنين لا يمكن أن تجعلهما متساويين أو متطابقين أبدًا.
لتحديد ما إذا كان هناك كائنان متساويان، لا يمكنك مقارنة ما إذا كانت مراجع الكائنين متساوية أم لا، فلن تحصل أبدًا على نتيجة متساوية لأن مرجعي الكائنين لن يكونا متساويين أبدًا، لذا فإن طريقة المقارنة الصحيحة هي المقارنة بينهما مباشرة. كائنين ومقارنة ما إذا كان جوهر الكائنين هو نفسه، أي ما إذا كانت محتويات الكائنين متماثلة، وتحديد ما إذا كان الكائنان متساويان من خلال مقارنة ما إذا كانت قيم السمات للكائنين هي نفسها.
توفر فئة الكائن طريقة يساوي () لمقارنة ما إذا كانت محتويات كائنين متماثلة، حتى نتمكن من استخدام هذه الطريقة لمقارنة ما إذا كان الكائنان "متساويان" منطقيًا. على سبيل المثال: c1.equals(c2); هنا يتم استدعاء أسلوب يساوي () الموروث من فئة الكائن. من خلال استشارة وثائق API، يكون تعريف أسلوب يساوي في فئة الكائن كما يلي:
القيمة المنطقية العامة تساوي (Object obj)
التنفيذ الافتراضي لطريقة Equals() المتوفرة في فئة الكائن هو مقارنة مرجع الكائن الحالي والمرجع الذي تريد مقارنته لمعرفة ما إذا كانا يشيران إلى نفس الكائن، وهو نفس "c1==c2" ". و"c1.equals(c2)" و"c1==c2" متكافئتان تمامًا. ولذلك، فإن استخدام طريقة يساوي () الموروثة مباشرة لا يمكن أن يقارن بشكل مباشر ما إذا كانت محتويات كائنين متماثلة. لهذا السبب، يجب علينا تجاوز طريقة يساوي () وتغيير التنفيذ الافتراضي لهذه الطريقة.
بعد ذلك، أعد كتابة طريقة يساوي () الموروثة في فئة القط:
class Cat { int color,weight, height; public Cat(int color, intweight, int height) { this.color = this.weight = this.height = height; تعمل طريقة يساوي () الموروثة من فئة الكائن على تغيير التنفيذ الافتراضي لهذه الطريقة * استخدم التنفيذ المحدد الخاص بنا لتحديد ما إذا كان الكائنان متساويان منطقيًا. * هنا نحدد أنه إذا كان لون ووزن وطول قطتين متماثلتين، * فإننا نعتقد أن القطتين متطابقتين منطقيا، أي أن القطتين "متساويتان". */ public boolean يساوي(Object obj){ if (obj==null){ return false } else{ /** * مثيل عامل الكائن. * يتم استخدام عامل تشغيل الكائن لتحديد ما إذا كان الكائن ينتمي إلى مثيل لفئة محددة أو فئة فرعية محددة. * عامل الكائن عبارة عن مثيل كلمة مدمج. * هذا العامل هو عامل ثنائي. التعبير الموجود على اليسار هو كائن والتعبير الموجود على اليمين هو فئة. * إذا كان الكائن الموجود على اليسار كائنًا تم إنشاؤه بواسطة الفئة الموجودة على اليمين، فإن نتيجة العملية هي صحيح، وإلا فهو كاذب. */ if (obj مثيل Cat){ Cat c = (Cat)obj; if (c.color==this.color && c.weight==this.weight && c.height==this.height){ return true; } } } إرجاع خطأ }} في هذا الوقت، قم بتنفيذ أمر الطباعة بالطريقة الرئيسية:
public static void main(String[] args) { /** * هنا، يتم استخدام طريقة البناء Cat() لإنشاء قطتين جديدتين في ذاكرة الكومة * اللون والوزن والارتفاع لهاتين القطتين متماثلتان * لكن c1 وc2 لن يكونا متساويين أبدًا، وذلك لأن c1 وc2 كائنان مرجعيان للقطتين في ذاكرة الكومة * يحتويان على العناوين التي يمكن العثور على القطتين فيها ذاكرة كومة في مساحتين مختلفتين، * لذا فإن c1 وc2 يحملان عنوانين مختلفين، لذا فإن c1 وc2 لن يكونا متساويين أبدًا. */ Cat c1 = new Cat(1, 1, 1); Cat c2 = new Cat(1, 1, 1); System.out.println("نتيجة c1==c2 هي:"+(c1== c2 ));//false System.out.println("نتيجة c1.equals(c2) هي: "+c1.equals(c2));//true }تختلف النتيجة التي تم الحصول عليها هذه المرة عن النتيجة التي تم الحصول عليها في المرة السابقة دون تجاوز طريقة يساوي () :
"System.out.println(c1 == c2);" لا تزال النتيجة المطبوعة خاطئة، لأن محتويات مرجعي الكائنين ليست متساوية بالطبع، ولن تكون كذلك أبدًا متساويان، لذا يجب أن تكون النتيجة المطبوعة خاطئة.
"System.out.println(c1.equals(c2));" النتيجة المطبوعة صحيحة، لأننا قمنا بإعادة كتابة طريقة يساوي () في فئة Cat وقمنا بتغيير التنفيذ الافتراضي لهذه الطريقة طريقة التغيير إلى فقط إذا كان هذين الكائنين موجودين بالفعل وكلاهما قطتان، وكان لونهما وطولهما ووزنهما واحدًا، فإن القطتين متطابقتان منطقيًا ومتطابقتان تمامًا، أي أن هاتين القطتين "متساويتان". وبالتالي فإن النتيجة المطبوعة هنا صحيحة.
فكيف يمكن مقارنة كائنين من السلسلة من أجل المساواة؟
انظر إلى المثال التالي:
public class TestEquals { public static void main(String args[]){ String s1 = new String("hello"); String s2 = new String("hello"); : "+(s1 == s2));//false System.out.println("نتيجة s1.equals(s2) هي:"+s1.equals(s2));//true }}هذه المرة تتم مقارنة كائني السلسلة من أجل المساواة:
System.out.println(s1 == s2);
لا تزال النتيجة المطبوعة خاطئة، لأن مرجعي كائني السلسلة s1 وs2 لن يكونا متساويين أبدًا، لذا فإن النتيجة المطبوعة خاطئة.
System.out.println(s1.equals(s2));
النتيجة المطبوعة صحيحة، لأن الوراثة من فئة الكائن تتم إعادة كتابتها في فئة السلسلة (جميع الفئات موروثة من فئة الكائن، وفئة السلسلة ليست استثناءً بالطبع. إذا ورثت من الفئة الأصل، فلديك كل شيء السمات والأساليب الخاصة بالفئة الأصلية، لذا فإن فئة Sting تحتوي أيضًا على طريقة يساوي () كما تمت إعادة كتابة طريقة يساوي () الموروثة)، مما يؤدي إلى تغيير التنفيذ الافتراضي لهذه الطريقة.
في فئة السلسلة، يتم تجاوز تنفيذ طريقة يساوي () على النحو التالي: مقارنة كائن السلسلة الحالي بكائن السلسلة المحدد لا يمكن أن يكون كائن السلسلة المحدد فارغًا وتسلسل الأحرف لهذا الكائن هو نفس السلسلة الحالية تسلسلات السلسلة للكائنات هي نفسها إذا تم استيفاء هذه الشروط، فإن كائني السلسلة متساويان.
لذلك، s2 هنا قد استوفى الشرط، وبالتالي فإن النتيجة المطبوعة صحيحة.
في المستقبل، عند مقارنة كائنين في فئة معينة للمساواة، انتقل أولاً إلى وثائق API لمعرفة ما إذا كانت هذه الفئة قد تجاوزت طريقة يساوي () الموروثة من فئة الكائن. إذا تم تجاوز طريقة يساوي ()، فسيتم استدعاء طريقة يساوي () التي تم تجاوزها عند مقارنة ما إذا كان هناك كائنان متساويان. إذا لم يتم تجاوزها، فسيتم استدعاء الطريقة الموروثة من فئة الكائن مباشرة يستخدم التنفيذ الافتراضي لطريقة يساوي () لمقارنة ما إذا كان هناك كائنان متساويان. لذلك، يمكن لكل فئة تجاوز طريقة يساوي () الموروثة من فئة الكائن حسب الحاجة.
للعثور على فئة معينة في مستند API، إذا كان من الممكن استخدام فئة مباشرة دون تقديم حزمة، فيجب أن تكون هذه الفئة في حزمة java.lang، على سبيل المثال، يمكن استخدام فئة String هنا مباشرة، لذلك يمكن استخدام فئة String يجب أن يكون موجودًا في حزمة java.lang. عند استخدام فئة معينة، تحقق من الحزمة التي يستوردها الفصل، ثم انتقل إلى الحزمة للعثور على الفئة، ويجب أن تكون الفئات التي لا تحتاج إلى استيراد الحزم موجودة في java.lang، فقط انتقل مباشرة إلى java.lang للعثور عليها .
بشكل عام، عندما نقوم بتصميم فئة، نحتاج إلى تجاوز طريقة يساوي للفئة الأصل. عند إعادة كتابة هذه الطريقة، نحتاج إلى تصميمها وفقًا للقواعد التالية:
1. الانعكاسية: بالنسبة لأي قيمة مرجعية X، يجب أن تكون القيمة المرجعة x.equals(x) صحيحة.
2. التناظر: بالنسبة لأي قيمة مرجعية x وy، إذا كانت القيمة المرجعة y.equals(x) صحيحة، يجب أن تكون القيمة المرجعة x.equals(y) صحيحة؛
3. العبورية: إذا كانت x.equals(y)=true، وy.equals(z)=true، فإن x.equals(z)=true
4. الاتساق: إذا لم تتغير الكائنات المشاركة في المقارنة، فيجب ألا تتغير نتيجة مقارنة الكائنات أيضًا.
5. عدم القابلية للإلغاء: بالنسبة لأي قيمة مرجعية غير فارغة X، يجب أن تكون القيمة المرجعة x.equals(null) خاطئة
على سبيل المثال:
public class People { public String firstName; public String getFirstName() { return firstName } public void setFirstName(String firstName) { this.firstName } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName } public int getAge() { return age } public void setAge(int age) { this.age = age; } @Override public boolean يساوي(Object obj) { if (this == obj) return true; return false; (!firstName.equals(other.firstName)) return false; if (lastName == null) { if (other.lastName != null) return false; ؛ إرجاع صحيح }}
في هذا المثال نشترط أن الشخص هو نفس الشخص إذا كان اسمه الأخير واسمه الأول وعمره واحدا. بالطبع، يمكنك أيضًا إضافة سمات أخرى، على سبيل المثال، يجب أن يكون رقم الهوية هو نفسه ليتم الحكم عليه على أنه نفس الشخص، ثم يمكنك إضافة حكم رقم الهوية بطريقة التساوي!
ملخص: لمقارنة ما إذا كان كائنان متساويان، نستخدم طريقة يساوي () تم تحديد شروط الحكم على ما إذا كان كائنان متساويان بعد إعادة كتابة تنفيذ طريقة يساوي () حتى تتمكن طريقة يساوي () من ذلك. يمكن استخدامها بشكل أكثر مرونة مقارنة كائنين من نفس الفئة في فئات مختلفة لمعرفة ما إذا كانا متساويين.