Αναφέρετε τη συμφωνία των μεθόδων hashCode και equals στη Java.
sobes.tech AI
Απάντηση από AI
Ο συμβολισμός των μεθόδων hashCode και equals στη Java καθορίζει τη σχέση τους και εγγυάται τη σωστή συμπεριφορά των αντικειμένων κατά τη χρήση συλλογών που βασίζονται σε πίνακες κατακερματισμού (π.χ., HashSet, HashMap).
Οι βασικοί κανόνες του συμβολαίου:
- Ανακλαστικότητα: Για οποιαδήποτε μη null αναφορά
x, τοx.equals(x)πρέπει να επιστρέφειtrue. - Αμφισημία: Για οποιεσδήποτε μη null αναφορές
xκαιy, τοx.equals(y)πρέπει να επιστρέφειtrueαν και μόνο αν τοy.equals(x)επιστρέφειtrue. - Μεταθετικότητα: Για οποιεσδήποτε μη null αναφορές
x,yκαιz, αν τοx.equals(y)και τοy.equals(z)είναιtrue, τότε τοx.equals(z)πρέπει να είναιtrue. - Συνεπτικότητα: Για οποιεσδήποτε μη null αναφορές
xκαιy, η επανειλημμένη κλήση τουx.equals(y)με τα ίδια αντικείμεναxκαιyπρέπει πάντα να επιστρέφει το ίδιο αποτέλεσμα. - Μη null: Για οποιαδήποτε μη null αναφορά
x, τοx.equals(null)πρέπει να επιστρέφειfalse.
Και ο βασικός κανόνας που συνδέει το hashCode και το equals:
- Αν δύο αντικείμενα είναι ίσα σύμφωνα με τη μέθοδο
equals(Object), τότε η κλήση της μεθόδουhashCode()για κάθε ένα από αυτά πρέπει να παράγει τον ίδιο ακέραιο αριθμό. - Αντίθετα, όχι ισχύει: αν δύο αντικείμενα έχουν τον ίδιο κωδικό κατακερματισμού, αυτό δεν σημαίνει ότι είναι ίσα.
Αξία του συμβολαίου:
Η παραβίαση του συμβολαίου μπορεί να οδηγήσει σε λανθασμένη λειτουργία των συλλογών. Για παράδειγμα, αν δύο ίσα αντικείμενα επιστρέφουν διαφορετικούς κωδικούς κατακερματισμού, το HashMap μπορεί να τα τοποθετήσει σε διαφορετικά "καλάθια" και να μην μπορέσει να βρει ένα αντικείμενο μέσω του άλλου, ακόμα και αν είναι λογικά ίσα.
Παράδειγμα σωστής υλοποίησης:
// Παράδειγμα κλάσης με σωστά `equals` και `hashCode`
public final class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Point point = (Point) o;
return x == point.x && y == point.y;
}
@Override
public int hashCode() {
int result = 17; // Μαγικό νούμερο, συνήθως πρώτο
result = 31 * result + x;
result = 31 * result + y;
return result;
}
// Getters (προαιρετικά για το παράδειγμα `equals`/`hashCode`)
public int getX() {
return x;
}
public int getY() {
return y;
}
}
Χρήση:
- Πάντα υπερκαλύψτε και τα δύο (
equalsκαιhashCode) μαζί. - Κατά τον υπολογισμό του
hashCode, χρησιμοποιήστε τα ίδια πεδία που χρησιμοποιούνται στοequals. - Προσπαθήστε να δημιουργήσετε "καλά" functions hash που διανέμουν ομοιόμορφα τους κωδικούς hash, ώστε να ελαχιστοποιήσετε τις συγκρούσεις (όταν διαφορετικά αντικείμενα έχουν τον ίδιο κωδικό hash) και να βελτιώσετε την απόδοση των κατακερματισμένων συλλογών.
- Για primitives, χρησιμοποιήστε τις τιμές τους. Για αντικείμενα, καλέστε το
hashCode(). Για πίνακες, χρησιμοποιήστε τις μεθόδους από τοArrays.
Στο Java 7+, για ευκολία και σωστή λειτουργία, συνιστάται η χρήση των Objects.equals(Object a, Object b) και Objects.hash(Object... values).
Παράδειγμα με Objects:
// Παράδειγμα κλάσης με `equals` και `hashCode` χρησιμοποιώντας `Objects`
import java.util.Objects;
public final class PointWithObjects {
private final int x;
private final int y;
public PointWithObjects(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PointWithObjects that = (PointWithObjects) o;
return x == that.x && y == that.y; // Η λογική σύγκρισης παραμένει
}
@Override
public int hashCode() {
return Objects.hash(x, y); // Βολική μέθοδος για υπολογισμό hash
}
}