عندما تجاوز متساوين في جاوة، فلماذا لا نعمل على استخدام معلمة أخرى من كائن؟

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

  •  08-07-2019
  •  | 
  •  

سؤال

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

وهنا كود أبسط من ذلك بكثير أن يظهر ما اراه:

public class MyClass {
  private int x;
  public MyClass(int n) { x = n; }
  public boolean equals(Object o) { return false; }
  public boolean equals(MyClass mc) { return x == mc.x; }
  public static void main(String[] args) {
    List<MyClass> list = new ArrayList<MyClass>();
    list.add(new MyClass(3));
    System.out.println("Contains 3? " + list.contains(new MyClass(3)));
  }
}

عند تشغيل هذا، فإنه يطبع "Contains 3? false". يبدو أن يتم استدعاء الدالة يساوى (وجوه)، على الرغم من وجود آخر من شأنه أن يعمل. على النقيض من ذلك، إذا أنا أكتب يساوي مثل هذا الرمز يعمل كما هو متوقع:

public boolean equals(Object o) {
  if(!(o instanceof MyClass))
    return false;
  MyClass mc = (MyClass)o;
  return x == mc.x;
}

لماذا أليس كذلك معرفة أي إصدار من وظيفة إلى استدعاء القائم على نوع المعلمة؟

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

المحلول

أنت الخلط بين "تجاوز" و "الحمولة الزائدة".

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

والحمولة الزائدة - إضافة الأسلوب مع نفس الاسم ولكن توقيع مختلف. ويتم اختيار طرق طاقتها في وقت الترجمة على أساس نوع وقت الترجمة من الكائن الهدف.

نصائح أخرى

ويساوى (وجوه) يتم تجاوز أسلوب السوبر. يمكنك <م> لا تجاوز أسلوب السوبر دون استخدام نفس التوقيع المحدد (حسنا، هناك بعض الاستثناءات مثل returntypes التغاير واستثناء).

لاحظ أن الطريقة التي تتصل وتعرف في جافادوك لArrayList<E> ك

boolean contains(Object o)
    Returns true if this list contains the specified element. 

وبدلا من

boolean contains(E o)
    Returns true if this list contains the specified element. 

وتنفيذ ArrayList.java:

private transient Object elementData[];

public boolean contains(Object elem) {
    return indexOf(elem) >= 0;
}

public int indexOf(Object elem) {
    if (elem == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (elem.equals(elementData[i]))
                return i;
    }
    return -1;
}

ويستخدم أسلوب متساوين المحددة في الطبقة المتفوقة كائن لأنه لا يتم تجاوز أسلوب متساوين في ArrayList<E> الصورة التنفيذ.

عند تساوي تجاوز كائن في جافا، يجب تجاوز أسلوب شفرة التجزئة كائن كذلك.

وعلى أي حال قد ترغب في محاولة التعليمة البرمجية التالية:

class A{    
    public int content;    
    A(){
        this(0);
    }    
    A(int value){
        content = value;
    }   
    public boolean equals(Object obj){
        System.out.println("overriding equals method");
        return this.content == ((A) obj).content;
    }    
    public boolean equals(A a){
        System.out.println("overloading equals method");
        return this.content == a.content;
    }    
    public static void main(String[] args){
        A x = new A(1);
        A y = new A(2);
        Object z  = new A(1);
        System.out.println(x.equals(y));
        System.out.println(x.equals(x));
        System.out.println(x.equals(z));
        //override as z is declared as Object at compile time
        //so it will use methods in class Object instead of class A
        System.out.println(x.equals((Object) y));
        System.out.println(x.equals((Object) x));        
    }   
}
//rant: they didn't teach me these in javaschool and I had to learn it the hard way.

ويلتزم تنفيذ ArrayList من (وجوه) طريقه يحتوي على استخدام Object.equals (وجوه) طريقه داخليا، لذلك سوف لا تعرف أبدا عن الحمولة الزائدة الخاص بك من طريقة متساوين (MyClass). ويمكن الاطلاع على طريقة الرئيسي فقط (مع مطابقة التوقيع).

وطيب اسمحوا لي أن أعيد العبارة.

و(1) لأن المترجم يلغي جميع المعلومات المتعلقة إلى الوراثة (المحو، انظر> وأ href = "http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#Type٪20Erasure" يختلط = "نوفولو noreferrer "> هنا )، و (2) لأنه لا يمكن تجاوز أسلوب دون نفس التوقيع المحدد (يساوى (وجوه))، (3) أثناء وقت التشغيل يتم التعامل مع كافة الكائنات داخل قائمة كما الأجسام وليس الحالات من MyClass. وبالتالي، فإن الأسلوب الذي يحصل على استدعاء هو يساوى (وجوه) لأن هذا هو واحد هو أن تم تجاوزها من قبل صفك.

وأنت على افتراض أن طريقة contains() في List يعرف نوع الكائن في وقت التشغيل، وهو غير صحيح.

ولأن المحو، ويصبح List<MyClass> مجرد List العادية في وقت التشغيل، لذلك يرى طريقة contains() به المعلمة باعتبارها Object، وبالتالي استدعاء equals() كائن بدلا من واحد قمت بتعريفه لMyClass في تنفيذه.

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