Kiedy tworzysz swój własny obiekt pary kluczy, powinieneś zmierzyć się z kilkoma rzeczami.
Po pierwsze, powinieneś być świadomy implementacji hashCode()
i equals()
. Będziesz musiał to zrobić.
Po drugie, podczas wdrażania hashCode()
upewnij się, że rozumiesz, jak to działa. Podany przykład użytkownika
public int hashCode() {
return this.x ^ this.y;
}
jest właściwie jedną z najgorszych implementacji, jakie możesz zrobić. Powód jest prosty: masz dużo równych haszów! A hashCode()
powinien zwrócić wartości int, które mają tendencję do być rzadki, wyjątkowy w najlepszym. Użyj czegoś takiego:
public int hashCode() {
return (X << 16) + Y;
}
Jest to szybkie i zwraca unikalne skróty dla kluczy od -2 ^ 16 do 2 ^ 16-1 (od -65536 do 65535). Pasuje to prawie do każdego przypadku. Bardzo rzadko jesteś poza tym zakresem.
Po trzecie, podczas implementacji equals()
wiedz również, do czego służy i bądź świadomy tego, jak tworzysz klucze, ponieważ są one obiektami. Często robisz to niepotrzebnie, jeśli stwierdzenia powodują, że zawsze będziesz miał ten sam rezultat.
Jeśli utworzysz klucze w ten sposób: map.put(new Key(x,y),V);
nigdy nie będziesz porównywać referencji swoich kluczy. Ponieważ za każdym razem, gdy chcesz uzyskać dostęp do mapy, zrobisz coś takiego map.get(new Key(x,y));
. Dlatego equals()
nie potrzebujesz takiego oświadczenia if (this == obj)
. To się nigdy nie wydarzy.
Zamiast if (getClass() != obj.getClass())
w equals()
lepszym użyciu if (!(obj instanceof this))
. Będzie obowiązywać nawet dla podklas.
Więc jedyne, co musisz porównać, to w rzeczywistości X i Y. Więc najlepsza equals()
implementacja w tym przypadku to:
public boolean equals (final Object O) {
if (!(O instanceof Key)) return false;
if (((Key) O).X != X) return false;
if (((Key) O).Y != Y) return false;
return true;
}
Ostatecznie twoja kluczowa klasa wygląda tak:
public class Key {
public final int X;
public final int Y;
public Key(final int X, final int Y) {
this.X = X;
this.Y = Y;
}
public boolean equals (final Object O) {
if (!(O instanceof Key)) return false;
if (((Key) O).X != X) return false;
if (((Key) O).Y != Y) return false;
return true;
}
public int hashCode() {
return (X << 16) + Y;
}
}
Możesz podać swoje indeksy wymiarów X
i Y
poziom dostępu publicznego, ponieważ są one ostateczne i nie zawierają poufnych informacji. Nie jestem w 100% pewien, czy private
poziom dostępu działa poprawnie w każdym przypadku podczas przesyłania Object
do pliku Key
.
Jeśli zastanawiasz się nad finałami, deklaruję wszystko jako ostateczne, którego wartość jest ustawiona na instancji i nigdy się nie zmienia - i dlatego jest stałą obiektową.