45 votes

Pourquoi la méthode equals dans String n'utilise-t-elle pas le hachage?

Le code de l' equals méthode de la classe String est

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) {
            char v1[] = value;
            char v2[] = anotherString.value;
            int i = offset;
            int j = anotherString.offset;
            while (n-- != 0) {
                if (v1[i++] != v2[j++])
                    return false;
            }
            return true;
        }
    }
    return false;
}

J'ai une question - pourquoi cette méthode utilise pas hashCode() ?

Autant que je sache, hashCode() permet de comparer deux chaînes de caractères rapidement.

Mise à JOUR: je sais, que deux inégale des chaînes, peut avoir le même hash. Mais l'égalité des deux chaînes de l'égalité des tables de hachage. Ainsi, en utilisant hashCode(), on peut voir immédiatement que les deux chaînes sont inégales.

Je suis tout simplement penser que l'utilisation de hashCode() peut être un bon filtre en equals.

Mise à JOUR 2: Voici un peu de code, nous parlons ici.

C'est un exemple de méthode de Chaîne est égale à peut ressembler à

public boolean equals(Object anObject) {
    if (this == anObject) {
        return true;
    }
    if (anObject instanceof String) {
        String anotherString = (String)anObject;
        if (hashCode() == anotherString.hashCode()){
            int n = count;
            if (n == anotherString.count) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = offset;
                int j = anotherString.offset;
                while (n-- != 0) {
                    if (v1[i++] != v2[j++])
                        return false;
                }
                return true;
            }
        }else{
            return false;
        }
    }
    return false;
}

40voto

parsifal Points 1340

Hashcode pourrait être un choix de première ronde pour vérifier l'inégalité. Cependant, il présente quelques compromis.

  1. String hashcodes sont paresseusement calculé, bien qu'ils utilisent le "gardien" de la valeur. Si vous êtes de la comparaison de chaînes de longue durée de vie (c'est à dire, ils sont susceptibles d'avoir eu le hashcode calculée), ce n'est pas un problème. Sinon, vous êtes coincé avec soit le calcul du hashcode (potentiellement onéreux) ou d'ignorer la case lorsque le hashcode n'a pas été encore calculé. Si vous avez beaucoup de courte durée de vie des chaînes, vous serez en ignorant le vérifier plus souvent que vous allez être l'utilisant.
  2. Dans le monde réel, la plupart des chaînes de caractères diffèrent dans leurs premiers caractères, de sorte que vous ne serez pas économiser beaucoup en cochant hashcode premier. Il y a, bien sûr, des exceptions (telles que les Url), mais encore une fois, dans le monde réel de la programmation qu'ils se produisent rarement.

15voto

assylias Points 102015

Cette question a en fait été considéré par les développeurs du JDK. Je ne pouvais pas trouver dans les différents messages, pourquoi il n'a pas été inclus. L'amélioration est également répertorié dans la base de données de bogues.

À savoir que le changement proposé est:

public boolean equals(Object anObject) {
    if (this == anObject) // 1st check identitiy
        return true;
    if (anObject instanceof String) { // 2nd check type
        String anotherString = (String)anObject;
        int n = count;
        if (n == anotherString.count) { // 3rd check lengths
            if (n != 0) { // 4th avoid loading registers from members if length == 0
                int h1 = hash, h2 = anotherString.hash;
                if (h1 != 0 && h2 != 0 && h1 != h2) // 5th check the hashes
                    return false;

Il y avait aussi une discussion à utiliser == pour les internés des chaînes de caractères (c'est à dire si les deux chaînes sont internés: if (this != anotherString) return false;).

7voto

MrSmith42 Points 5159

1) Le calcul de hashCode n'est peut-être pas plus rapide que la comparaison directe des chaînes.

2) si le hashCode est égal, les chaînes peuvent toujours ne pas être égales

4voto

irreputable Points 25577

Cela peut être une bonne idée pour de nombreux cas d'utilisation.

Cependant, en tant que fondation de la classe qui est largement utilisé dans toutes sortes d'applications, l'auteur n'a vraiment aucune idée de savoir si cette vérification supplémentaire peut enregistrer ou de nuire à la performance moyenne.

Je vais deviner que la majorité des String.equals() sont invoqués dans une table de hachage, après les codes de hachage a été connu pour être égaux, de sorte que les tests des codes de hachage, de nouveau, est inutile.

Si l'on considère la comparaison de 2 chaînes aléatoires, même avec un petit char comme NOUS l'ASCII, il est très probable que les hachages sont différents, et le char par char comparaison échoue sur le 1er char. Donc ça va être une perte pour vérifier les tables de hachage.

2voto

Peter Lawrey Points 229686

Autant que je sache, le contrôle suivant pourrait être ajouté à String. Ceci vérifie que si les codes de hachage sont définis et différents, les chaînes ne peuvent pas être égales.

 if (hash != 0 && anotherString.hash != 0 && hash != anotherString.hash)
    return false;
if (hash32 != 0 && anotherString.hash32 != 0 && hash32 != anotherString.hash32)
    return false;
 

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X