Wenn equals in Java überschreiben, warum funktioniert es nicht einen anderen Parameter als Objekt zu benutzen?

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

  •  08-07-2019
  •  | 
  •  

Frage

Ich lief in ein interessantes Verhalten vor kurzem. Es scheint, dass, wenn ich .equals () außer Kraft setzen einen anderen Parameter als Objekt zu nehmen, ist es nicht aufgerufen. Kann jemand mir erklären, warum dies geschieht? Es scheint, mein Verständnis von Polymorphismus in OOP zu verletzen, aber vielleicht bin ich etwas fehlt.

Hier ist viel einfacher Code, das zeigt, was ich sehe:

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)));
  }
}

Wenn diese ausgeführt wird, druckt es „Contains 3? false“. Es sieht aus wie die equals (Object) Funktion aufgerufen wird, obwohl es eine andere ist, die funktionieren würde. Im Gegensatz dazu, wenn ich schreibe, ist gleich wie dies der Code wie erwartet funktioniert:

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

Warum ist es nicht herauszufinden, welche Version der Funktion von der Art des Parameters basierend anrufen?

War es hilfreich?

Lösung

Sie vermischen "überschreiben" und "Überlastung".

Übergeordnete - Hinzufügen einer Ersatz Definition eines bestehendes Verfahren zum Zweck des Polymorphismus. Die Methode muss die gleiche Signatur haben. Die Signatur besteht aus dem Namen und Argumenttypen. Überschriebenen Methoden werden zur Laufzeit ausgewählt basierend auf dem Laufzeittyp des Zielobjekts.

Eine Überlastung - ein Verfahren, mit dem gleichen Namen addiert, sondern eine andere Signatur. Überladene Methoden bei der Kompilierung ausgewählt werden auf der Grundlage der Kompilierung Typ des Zielobjekts.

Andere Tipps

equals (Object) überschreibt eine Super-Methode; Sie können nicht eine Super-Methode überschreiben, ohne genau die gleiche Signatur (Na ja, es gibt einige Ausnahmen wie covariant returntypes und Ausnahme).

Beachten Sie, dass die Methode, die Sie definiert im javadoc für ArrayList<E> wie

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

statt

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

Die Umsetzung von 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;
}

Es verwendet die Methode equals in der Objektsuperklasse definiert, da die Methode equals nicht in ArrayList<E> 's Implementierung außer Kraft gesetzt wird.

Wenn Objekt überschreiben in Java entspricht, sollten Sie das Objekt hashCode Methode als auch außer Kraft setzen.

Auf jeden Fall sollten Sie den folgenden Code ein, um zu versuchen:

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.

Die Arraylist Umsetzung des enthält (Object) -Methode gebunden intern Object.equals (Object) Methode zu verwenden, so dass es nie über Ihre Überlastung des equals (MyClass) -Methode wissen werden. Nur ein überwiegendes Verfahren (mit Unterschrift entspricht) gefunden werden.

Ok lassen Sie mich wieder Satz.

(1) Da die Compiler alle Informationen beseitigt zu Generics in Bezug auf (Löschen finden Sie unter hier ) und (2), weil Sie eine Methode ohne die exakt gleiche Signatur nicht überschreiben können (equals (Object)), (3) während der Laufzeit alle Objekte in der Liste werden als Objekte und nicht als Instanzen behandelt von MyClass. Daher ist die Methode, die ist equals (Object) aufgerufen wird, da dies der einzige ist, die von Ihrer Klasse überschrieben worden ist.

Sie gehen davon aus, dass die contains() Methode in List die Art des Objekts zur Laufzeit weiß, was falsch ist.

Aufgrund der Löschung List<MyClass> wird nur eine ganz normale List zur Laufzeit, so dass die contains() Methode seine Parameter als Object sieht, so Objekt equals() anstelle des einen Aufruf Sie MyClass definiert in seiner Ausführung.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top