Hier ist eine schöne Falle, auf die ich gerade gestoßen bin. Betrachten Sie eine Liste von ganzen Zahlen:
List<Integer> list = new ArrayList<Integer>();
list.add(5);
list.add(6);
list.add(7);
list.add(1);
Irgendwelche fundierten Vermutungen darüber, was passiert, wenn Sie ausführen list.remove(1)
? Was ist mit list.remove(new Integer(1))
? Dies kann einige böse Fehler verursachen.
Was ist der richtige Weg, um zu unterscheiden remove(int index)
, was ein Element aus einem bestimmten Index entfernt und remove(Object o)
was ein Element durch Bezugnahme entfernt, wenn es sich um Listen von ganzen Zahlen handelt?
Der wichtigste Punkt, der hier berücksichtigt werden muss, ist der erwähnte @Nikita - die genaue Parameterübereinstimmung hat Vorrang vor dem automatischen Boxen.
java
collections
overloading
Yuval Adam
quelle
quelle
Antworten:
Java ruft immer die Methode auf, die am besten zu Ihrem Argument passt. Auto-Boxing und implizites Upcasting werden nur durchgeführt, wenn es keine Methode gibt, die ohne Casting / Auto-Boxing aufgerufen werden kann.
Die List-Schnittstelle gibt zwei Entfernungsmethoden an (bitte beachten Sie die Benennung der Argumente):
remove(Object o)
remove(int index)
Dies bedeutet, dass
list.remove(1)
das Objekt an Position 1remove(new Integer(1))
entfernt und das erste Vorkommen des angegebenen Elements aus dieser Liste entfernt wird.quelle
Integer.valueOf(1)
ist besser alsnew Integer(1)
. Die statische Methode kann Caching und dergleichen ausführen, um eine bessere Leistung zu erzielen.new Integer(1)
, aber ich stimme dem zuInteger.valueOf(1)
oder bin(Integer) 1
gleichwertig.Sie können Casting verwenden
und
Es spielt keine Rolle, ob n ein int oder eine Ganzzahl ist, die Methode ruft immer die erwartete auf.
Die Verwendung von
(Integer) n
oderInteger.valueOf(n)
ist effizienter alsnew Integer(n)
die ersten beiden, die den Integer-Cache verwenden können, während die letztere immer ein Objekt erstellt.quelle
Ich weiß nicht, wie man es richtig macht, aber die von Ihnen vorgeschlagene Art funktioniert einwandfrei:
entfernt das Element an der angegebenen Position und
Entfernt ein bestimmtes Objekt aus der Liste.
Dies liegt daran, dass VM zunächst versucht, eine Methode zu finden, die mit genau demselben Parametertyp deklariert wurde , und erst dann versucht, eine Autobox durchzuführen.
quelle
list.remove(4)
ist eine genaue Übereinstimmung vonlist.remove(int index)
, so wird es aufgerufen. Wenn Sie anrufen möchten,list.remove(Object)
gehen Sie wie folgt vor :list.remove((Integer)4)
.quelle
(Integer)
Besetzung, wie Sie sie oben geschrieben haben, scheint für mich der einfachste Ansatz zu sein.Es besteht kein Grund zu raten. Der erste Fall führt dazu,
List.remove(int)
dass aufgerufen wird und das Element an der Position1
entfernt wird. Der zweite Fall führt dazu,List.remove(Integer)
dass aufgerufen wird und das Element, dessen Wert gleichInteger(1)
ist, entfernt wird. In beiden Fällen wählt der Java-Compiler die am besten passende Überladung aus.Ja, hier besteht die Gefahr von Verwirrung (und Fehlern), aber es ist ein ziemlich ungewöhnlicher Anwendungsfall.
Als die beiden
List.remove
Methoden in Java 1.2 definiert wurden, waren die Überladungen nicht mehrdeutig. Das Problem trat erst mit der Einführung von Generika und Autoboxing in Java 1.5 auf. Im Nachhinein wäre es besser gewesen, wenn eine der Entfernungsmethoden einen anderen Namen erhalten hätte. Aber jetzt ist es zu spät.quelle
Beachten Sie, dass Sie auch dann, wenn die VM nicht das Richtige getan hat, das richtige Verhalten sicherstellen können, indem Sie die Tatsache verwenden, dass
remove(java.lang.Object)
mit beliebigen Objekten gearbeitet wird:quelle
equals
Methode, insbesondere (aus dem Javadoc). "Sie ist symmetrisch: Für alle Nicht-Null-Referenzwerte x und y sollte x.equals (y) genau dann true zurückgeben, wenn y.equals ( x) gibt true zurück. ". Als solches ist es nicht garantiert, dass es bei allen Implementierungen von funktioniertList
, da jede Implementierung von List das x und das y nachx.equals(y)
Belieben austauschen darf, da der Javadoc vonObject.equals
sagt, dass dies gültig sein sollte.Ich habe einfach gerne gefolgt, wie von #decitrig in der akzeptierten Antwort als erster Kommentar vorgeschlagen.
Das hat mir geholfen. Nochmals vielen Dank #decitrig für Ihren Kommentar. Es kann für jemanden helfen.
quelle
Nun, hier ist der Trick.
Nehmen wir hier zwei Beispiele:
Schauen wir uns nun die Ausgabe an:
Lassen Sie uns nun die Ausgabe analysieren:
Wenn 3 aus der Sammlung entfernt wird, wird die
remove()
Methode der Sammlung aufgerufen, dieObject o
als Parameter verwendet wird. Daher wird das Objekt entfernt3
. Im ArrayList-Objekt wird es jedoch durch Index 3 überschrieben, und daher wird das 4. Element entfernt.Nach der gleichen Logik der Objektentfernung wird in beiden Fällen in der zweiten Ausgabe null entfernt.
Um die Zahl zu entfernen, die
3
ein Objekt ist, müssen wir explizit 3 als übergebenobject
.Dies kann durch Casting oder Wrapping mit der Wrapper-Klasse erfolgen
Integer
.Z.B:
quelle