Ich denke, ich habe es endlich herausgefunden. Das hat Kopfkratzen gekostet. Gute Frage.
Moral der Geschichte: Ich denke, Sie sind in ein bisschen Verrücktheit mit der hashCode()
Funktion gestolpert. Die hashCode()
Funktion muss einen int
Wert zurückgeben, aber Sie geben einen float
Wert zurück.
Um Ihr Problem zu beheben, werfen Sie einfach den hash
Wert in eine int
vor der Rückgabe!
public int hashCode() {
int hash = 17;
hash = ((hash + x) << 5) - (hash + x);
hash = ((hash + y) << 5) - (hash + y);
return (int)hash;
}
Das mag seltsam und unnötig erscheinen, also hier eine längere Erklärung:
Beachten Sie, dass x
und y
sind float
Werte, so dass, wenn Sie sie in Ihrer hash
Berechnungen verwenden, wird das Ergebnis eine float
als Gut. Sie können dies nachweisen, indem Sie den Wert hash
vor der Rückgabe ausdrucken.
Java würde sich darüber beschweren. Sie können dies nachweisen, indem Sie einfach in den Java-Modus wechseln und versuchen, Ihr Programm auszuführen. Aber JavaScript ist nicht so streng mit seinen Typen, so dass Sie sich in den Fuß schießen können. Etwas, was ich normalerweise mache, ist im Java-Modus zu programmieren, um seine Fehlerprüfung zu erhalten, und dann im JavaScript-Modus zu implementieren.
Wie auch immer, innerhalb der HashMap
Klasse wird das Ergebnis der hashCode()
Funktion schließlich als ein Index in einem Array verwendet. Sie können in der Processing.js Quelldatei, die sie sehen:
//this is in the HashMap class
function getBucketIndex(key) {
var index = virtHashCode(key) % buckets.length;
return index < 0 ? buckets.length + index : index;
}
function virtHashCode(obj) {
if (obj.hashCode instanceof Function) {
return obj.hashCode();
}
//other code omitted to keep this short
}
Und das könnte in Ordnung sein, denn seltsamerweise JavaScript mit Dezimalstellen in Array-Indizes in Ordnung ist. Aber das Problem ist die Implementierung von HashSet's
Iterator
:
function Iterator(conversion, removeItem) {
var bucketIndex = 0;
var itemIndex = -1;
var endOfBuckets = false;
var currentItem;
function findNext() {
while (!endOfBuckets) {
++itemIndex;
if (bucketIndex >= buckets.length) {
endOfBuckets = true;
} else if (buckets[bucketIndex] === undef || itemIndex >= buckets[bucketIndex].length) {
itemIndex = -1;
++bucketIndex;
} else {
return;
}
}
}
//more code
Check-out, dass findNext()
Funktion. Es durchläuft die Indizes des Arrays, wird aber jedes Mal um eins erhöht. Daher werden alle Schlüssel, die in Dezimalstellenindizes eingefügt werden, übersprungen!
Aus diesem Grund überspringt Ihr Iterator eines Ihrer Objekte (das mit einer Dezimalstelle in dem von hashCode()
zurückgegebenen Wert). Und deshalb schlägt auch toArray()
fehl, da diese Funktion eine Iterator
unter der Haube verwendet.
Ich würde dies nicht wirklich einen Fehler nennen, da das Problem durch die Rückgabe eines float
von einer Funktion verursacht wird, die besagt, dass es eine int
zurückgibt. JavaScript benötigt nicht wirklich hashCode()
funktioniert auf die gleiche Weise wie Java, so dass diese Implementierung von HashMap
und Iterator
ziemlich vernünftig ist. Sie müssen nur sicherstellen, dass Sie eine int
aus der hashCode()
Funktion zurückgeben.
By the way, hier ist ein kleines Beispiel, wenn Sie wie das Spiel umhertasten:
class Thing {
int myThing;
public Thing(int myThing) {
this.myThing = myThing;
}
public int hashCode(){
return myThing;
}
public boolean equals(Object obj) {
Thing other = (Thing) obj;
return (myThing == other.myThing);
}
}
void setup() {
HashMap<Thing, String> map = new HashMap<Thing, String>();
map.put(new Thing(1), "A");
map.put(new Thing(2.5), "B"); //uh oh!
map.put(new Thing(3), "C");
println("1, " + map.size()); // outputs 3
println("2, " + map.keySet().size()); // outputs 3
println("3, " + map.keySet().toArray().length); // outputs 2
}
Bitte senden Sie ein [MCVE], die wir zeigt genau den Code Sie ausführen. Beachten Sie, dass dies nur ein paar Zeilen sein sollte, gerade genug für uns zum Kopieren und Einfügen, um die gleichen Ergebnisse zu erhalten, aber nicht Ihre ganze Skizze! –
Dieser Code funktioniert gut für mich: 'HashMap map = neue HashMap (); map.put ("eins", "A"); map.put ("zwei", "B"); map.put ("drei", "C"); println (map.size()); println (map.keySet(). ToArray(). Length); ' –
Ah, danke Kevin! Entschuldigung für das unvollständige Beispiel. Deine Antwort hat mich dazu gebracht, auf niedrigerer Ebene zu debuggen. Mein Problem stellte sich heraus, dass die Schlüssel in meiner HashMap Objekte waren, und der HashCode, den ich für diese Objekte erstellt hatte, scheiterte aufgrund einer falschen Verwendung eines Floats. Ich verstehe immer noch nicht, warum die Aufrufe von keySet(). Size() und keySet() .toArray(). Length zu unterschiedlichen Werten führten. Ich poste ein aktuelles Codebeispiel mit dem, was mir wirklich in den Sinn gekommen ist, falls jemand interessiert ist. Danke noch einmal! – megabits