Ich habe neulich mit einem gearbeitet HashSet
, der dies in der Spezifikation geschrieben hat:
[add ()] fügt das angegebene Element e zu dieser Menge hinzu, wenn diese Menge kein Element e2 enthält, so dass (e == null? e2 == null: e.equals (e2))
Ich habe char[]
in der verwendet, HashSet
bis mir klar wurde, dass es aufgrund dieses Vertrags nicht besser war als ein ArrayList
! Da das nicht überschriebene .equals()
Array verwendet wird, werden meine Arrays nur auf Referenzgleichheit überprüft, was nicht besonders nützlich ist. Ich weiß, dass Arrays.equals()
es das gibt, aber das hilft nicht, wenn man Sammlungen wie verwendet HashSet
.
Meine Frage ist also, warum Java-Arrays nicht gleich überschreiben sollten.
java
language-design
array
Azar
quelle
quelle
n
Speichersteckplätze, die groß genug sind, um jeweils einen Wert desT
nacheinander geklebten Typs aufzunehmen . Sie sind die Bausteine für anspruchsvollere kurzlebige Sammlungen. Was Sie wollten, war einList
.toString()
Darstellung ist größtenteils nutzlos und es gibt fast keinen Vorteil, jemals eines gegenüber einem zu verwendenArrayList
.Map<Key, int[]>
hat sich immer natürlich angefühlt. Aber ich bin immer nervös, dass etwas Schreckliches auf mich wartetAntworten:
In Java musste frühzeitig eine Entwurfsentscheidung getroffen werden:
Die Antwort ist, weder wirklich ... noch beides, wenn man es anders betrachtet. Sie arbeiten ziemlich eng mit dem System selbst und dem Backend des JVM zusammen.
Ein Beispiel hierfür ist die Methode java.lang.System.arraycopy () , für die ein Array eines beliebigen Typs erforderlich ist. Daher muss das Array in der Lage sein, etwas zu erben , und das ist ein Objekt. Und Arraycopy ist eine native Methode.
Arrays sind auch in komisch , dass sie Primitiven halten können (
int
,char
,double
, etc ... , während die anderen Sammlungen nur Objekte halten kann. Schauen Sie zum Beispiel bei java.util.Arrays und die hässliche Seite des Gleichheits Methoden. Dies wurde gestellt in eine als nach Gedanken. deepEquals (Object [], Object []) wurde bis 1,5 , während der Rest der Klasse Arrays in 1.2 hinzugefügt wurde nicht hinzugefügt.Da es sich bei diesen Objekten um Arrays handelt, können Sie einige Dinge ausführen , die sich im Speicher oder in der Nähe des Speichers befinden - etwas, das Java häufig vor dem Codierer verbirgt. Dies ermöglicht es, bestimmte Dinge schneller zu erledigen, wenn das Objektmodell größtenteils beschädigt wird.
Zu Beginn des Systems gab es einen Kompromiss zwischen Flexibilität und etwas Leistung. Die Leistung siegte und der Mangel an Flexibilität wurde in die verschiedenen Kollektionen eingewickelt. Arrays in Java sind ein dünn implementiertes Objekt über einem primitiven Typ (ursprünglich), der für die Arbeit mit dem System vorgesehen ist, wenn Sie es benötigen.
Zum größten Teil waren rohe Arrays Dinge, die die ursprünglichen Designer anscheinend nur im System zu ignorieren und zu verstecken versuchten. Und sie wollten, dass es schnell geht (frühes Java hatte einige Probleme mit der Geschwindigkeit). Es war eine Warze im Design, dass Arrays keine schönen Arrays sind, aber es war eine, die benötigt wurde, wenn Sie etwas so nah wie möglich am System verfügbar machen wollten. Übrigens haben auch die heutigen Sprachen des frühen Java diese Warze - man kann kein
.equals()
Array auf C ++ machen.Java und C ++ haben beide denselben Pfad für Arrays eingeschlagen - eine externe Bibliothek, die die erforderlichen Operationen für Arrays anstelle von Arrays ausführt ... und den Codierern vorschlägt, bessere native Typen zu verwenden, sofern sie nicht wirklich wissen, was sie tun und warum sie es sind mach es so.
Daher ist der Ansatz, .equals in ein Array zu implantieren, falsch, aber es ist der gleiche Fehler, den Codierer aus C ++ kannten. Wählen Sie also das am wenigsten Falsche in Bezug auf die Leistung - lassen Sie es als Implementierung von Object: Zwei Objekte sind genau dann gleich, wenn sie sich auf dasselbe Objekt beziehen.
Das Array muss eine primitive Struktur haben, um mit nativen Bindungen kommunizieren zu können - etwas, das dem klassischen C-Array so nahe wie möglich kommt. Im Gegensatz zu den anderen Grundelementen muss das Array jedoch als Referenz und damit als Objekt übergeben werden können. Es ist also eher ein Primitiv mit einigen Objekt-Hacks an der Seite und einigen Grenzüberprüfungen.
quelle
In Java sind Arrays Pseudoobjekte. Objektreferenzen können Arrays enthalten und verfügen zwar über die Standardobjektmethoden, sind jedoch im Vergleich zu einer echten Sammlung sehr leicht. Arrays tut gerade genug , um den Auftrag eines Objekts und verwenden Sie die Standardimplementierungen von gerecht zu werden
equals
,hashCode
undtoString
ganz bewusst.Betrachten Sie eine
Object[]
. Ein Element dieses Arrays kann alles sein, was in ein Objekt passt, einschließlich eines anderen Arrays. Es könnte ein primitives Kästchen sein, eine Steckdose, alles. Was bedeutet Gleichheit in diesem Fall? Nun, es hängt davon ab, was sich tatsächlich im Array befindet. Dies ist im allgemeinen Fall, als die Sprache entworfen wurde, nicht bekannt. Gleichheit wird sowohl durch das Array selbst als auch durch seinen Inhalt definiert .Dies ist der Grund, warum es eine
Arrays
Hilfsklasse gibt, die Methoden zur Berechnung von Gleichheit (einschließlich Deep Equals), Hash-Codes usw. enthält. Diese Methoden sind jedoch in Bezug auf ihre Funktionsweise genau definiert. Wenn Sie unterschiedliche Funktionen benötigen, schreiben Sie Ihre eigene Methode, um zwei Arrays auf Gleichheit zu vergleichen, basierend auf den Anforderungen Ihres Programms.Obwohl dies keine reine Antwort auf Ihre Frage ist, ist es meiner Meinung nach wichtig zu sagen, dass Sie wirklich Sammlungen anstelle von Arrays verwenden sollten. Konvertieren Sie nur in ein Array, wenn Sie eine Schnittstelle zu einer API herstellen, für die Arrays erforderlich sind. Andernfalls bieten Sammlungen eine bessere Typensicherheit, klarere Verträge und sind im Allgemeinen einfacher zu verwenden als Arrays.
quelle
Arrays.equals()
für eine tiefe Gleichheit gesorgt haben .Die grundlegende Schwierigkeit beim Überschreiben von Arrays
equals
besteht darin, dass eine Variable eines Typs wieint[]
auf mindestens drei grundlegend unterschiedliche Arten verwendet werden kann und die Bedeutung vonequals
je nach Verwendung variieren sollte. Insbesondere ein Feld vom Typint[]
...... kann eine Folge von Werten in einem Array kapseln, die niemals geändert werden, aber frei mit Code geteilt werden können, der sie nicht ändert.
... kann das ausschließliche Eigentum an einem Container mit ganzzahligen Bestandteilen enthalten, der von seinem Eigentümer nach Belieben mutiert werden kann.
... kann einen ganzzahligen Container identifizieren, den eine andere Entität verwendet, um ihren Status zu kapseln, und somit als Verbindung zum Status dieser anderen Entität dienen.
Wenn eine Klasse ein HAS -
int[]
Feld ,foo
das für eine der ersten zwei Zwecke verwendet wird, dann Fällex
undy
sollen betrachtenx.foo
undy.foo
als den gleichen Zustand einkapselt , wenn sie dieselbe Folge von Zahlen halten; wenn das Feld für den dritten Zweck verwendet wird, jedoch dannx.foo
undy.foo
würde nur den gleichen Zustand verkapseln , wenn sie identifizieren die gleiche Array [dh sie sind Referenz gleich]. Wenn Java für die drei oben genannten Verwendungen unterschiedliche Typen aufgenommen hätte undequals
einen Parameter verwendet hätte, der angibt, wie die Referenz verwendet wird, wäre es angemessen gewesenint[]
, die Sequenzgleichheit für die ersten beiden Verwendungen und die Referenzgleichheit für die dritte zu verwenden. Es gibt jedoch keinen solchen Mechanismus.Beachten Sie auch, dass der
int[]
Fall die einfachste Art von Array war. Für Arrays, die Verweise auf andere Klassen alsObject
oder Array-Typen enthalten, gibt es zusätzliche Möglichkeiten.Ein Verweis auf ein gemeinsam nutzbares, unveränderliches Array, das Dinge enthält, die sich nie ändern werden.
Ein Verweis auf ein gemeinsam nutzbares, unveränderliches Array, das Dinge identifiziert, die anderen Entitäten gehören.
Ein Verweis auf ein exklusives Array, das Verweise auf Dinge enthält, die sich nie ändern werden.
Ein Verweis auf ein Array, das ausschließlich Eigentum ist und Verweise auf Elemente enthält, die ausschließlich Eigentum sind.
Ein Verweis auf ein ausschließlich im Besitz befindliches Array, das Dinge identifiziert, die anderen Entitäten gehören.
Eine Referenz, die ein Array identifiziert, das einer anderen Entität gehört.
In den Fällen 1, 3 und 4 sollten zwei Array-Referenzen als gleich angesehen werden, wenn die entsprechenden Elemente "gleichwertig" sind. In den Fällen 2 und 5 sollten zwei Array-Referenzen als gleich angesehen werden, wenn sie dieselbe Folge von Objekten identifizieren. In Fall 6 sollten zwei Array-Referenzen nur dann als gleich angesehen werden, wenn sie dasselbe Array identifizieren.
Um
equals
sich mit Aggregattypen sinnvoll zu verhalten, müssen sie wissen, wie Referenzen verwendet werden. Leider kann das Java-Typsystem dies nicht anzeigen.quelle
Wenn Sie das Array überschreiben
equals()
undhashCode()
vom Inhalt abhängig sind, ähneln sie Sammlungen - veränderlichen Typen mit nicht konstanten WertenhashCode()
. Typen mit ÄnderungenhashCode()
verhalten sich schlecht, wenn sie in Hash-Tabellen und anderen Anwendungen gespeichert werden, die aufhashCode()
festen Werten basieren .Arrays hingegen haben einen trivialen hashCode (), können als Hash-Tabellenschlüssel verwendet werden und sind weiterhin veränderbar.
quelle
int[]
Typarray.