web-dev-qa-db-fra.com

Le hashCode de Java peut-il produire la même valeur pour différentes chaînes?

Est-il possible d'avoir le même hashcode pour différentes chaînes en utilisant la fonction de hashcode de Java ou s'il est possible alors quel est le% de sa possibilité?

36
Xara

Un code de hachage Java est 32bits. Le nombre de chaînes possibles qu'il hache est infini. 

Alors oui, il y aura des collisions. Le pourcentage n'a pas de sens - il existe un nombre infini d'éléments (chaînes) et un nombre fini de hachages possibles.

54
Mat

OUI. Beaucoup. 

Regardez la paire suivante

  • "FB" et "Ea" 

peut retourner le même code de hachage même si les caractères qu'il contient ne sont pas identiques.

Fondamentalement, il s’agit de la somme des caractères d’une chaîne multipliée par un entier.

19
titogeo

si c'est possible alors quel est le% de sa possibilité?

Ce n'est pas une question particulièrement significative.

Toutefois, sauf en cas de biais systémiques dans la fonction String::hashcode ou dans la manière dont vous générez les objets String, la probabilité que deux objets String différents (non égaux) aient le même code de hachage sera de 1 sur 2.32.

Cela suppose que les chaînes sont choisies au hasard parmi l'ensemble des valeurs de chaîne possibles. Si vous limitez le jeu de différentes manières, la probabilité sera différente du nombre ci-dessus. (Par exemple, l'existence de la collision "FB"/"Ea" signifie que la probabilité d'une collision dans l'ensemble des chaînes de 2 lettres est supérieure à la norme.)


Une autre chose à noter est que la chance de 232 différentes chaînes choisies au hasard (dans un ensemble de chaînes non biaisé beaucoup plus important) n'ayant pas de collision de hachage sont en voie de disparition de petite taille. Pour comprendre pourquoi, lisez la page Wikipedia sur le Birthday Paradox

En réalité, la seule façon de ne pas avoir de collisions de hachage dans un ensemble de 232 différentes chaînes est si vous sélectionnez ou générez les chaînes. Même former l'ensemble en sélectionnant des chaînes générées aléatoirement va coûter cher en calcul. Pour produire efficacement un tel ensemble, vous devez exploiter les propriétés de l'algorithme String::hashCode, qui (heureusement) est spécifié.

8
Stephen C

Oui, c'est tout à fait possible. La probabilité qu'une chaîne (ou un autre type d'objet - en supposant que vous utilisiez des chaînes dans cet exemple) ayant le même hashcode qu'une autre chaîne d'une collection, dépend de la taille de cette collection (en supposant que toutes cette collection sont uniques). Les probabilités sont réparties comme suit:

  • Avec un ensemble de taille ~ 9 000, vous aurez 1% de chances que deux chaînes entrent en collision avec un dièse dans l'ensemble
  • Avec un ensemble de taille ~ 30 000, vous aurez 10% de chances que deux chaînes entrent en collision avec un dièse dans l'ensemble
  • Avec un ensemble de taille ~ 77 000, vous aurez 50% de chances que deux chaînes entrent en collision avec un dièse dans l'ensemble

Les hypothèses retenues sont:

  • La fonction hashCode n'a pas de biais
  • Chaque chaîne de cet ensemble est unique

Ce site l'explique clairement: http://eclipsesource.com/blogs/2012/09/04/the-3-things-you-should-know-about-hashcode/ (Regardez "le deuxième chose à savoir ")

8
NSV

Cela ne répondrait pas directement à votre question, mais j'espère que cela vous aidera.

Le ci-dessous provient du code source de Java.lang.String.

/**
 * Returns a hash code for this string. The hash code for a
 * <code>String</code> object is computed as
 * <blockquote><pre>
 * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
 * </pre></blockquote>
 * using <code>int</code> arithmetic, where <code>s[i]</code> is the
 * <i>i</i>th character of the string, <code>n</code> is the length of
 * the string, and <code>^</code> indicates exponentiation.
 * (The hash value of the empty string is zero.)
 *
 * @return  a hash code value for this object.
 */
public int hashCode() {
    int h = hash;
    int len = count;
    if (h == 0 && len > 0) {
    int off = offset;
    char val[] = value;

        for (int i = 0; i < len; i++) {
            h = 31*h + val[off++];
        }
        hash = h;
    }
    return h;
}
6
adarshr

Oui, il est possible que deux chaînes aient le même hashcode - Si vous jetez un coup d'œil à l'article de Wikipedia , vous verrez que "FB" et "Ea" ont le même hashcode. Dans le contrat de méthode, rien n’indique qu’on devrait utiliser hashCode() pour comparer, vous souhaitez utiliser equals() pour cela.

Depuis Java 1.2, String implémente hashCode() en en utilisant un algorithme de somme de produit sur l’ensemble du texte de la chaîne .

5
Marcelo

Oui, par définition du concept de pigeon-trou, deux chaînes différentes peuvent produire le même hashcode et le code doit toujours être écrit pour répondre à de telles conditions (généralement, en ne cassant pas.)

4
Jaco Van Niekerk

Le pourcentage de collisions pour les chaînes random doit être minimal. Toutefois, si vous utilisez des chaînes de hachage provenant de sources externes, un attaquant pourrait facilement créer des centaines de milliers de chaînes ayant le même code de hachage. Dans une carte de hachage Java, ces éléments seraient tous mappés vers le même seau et transformeraient efficacement la carte en une liste chaînée. Les temps d’accès à la carte seraient alors proportionnels à la taille de la carte et non constants, ce qui donnerait lieu à une attaque par déni de service.

Voir cette page sur Attaques DoS efficaces contre les plates-formes d’application Web pour plus d’informations sur les liens vers la présentation.

2
Jörn Horstmann

Oui, cela est possible, car l'un des contrats entre equals () et la méthode hashCode () de la classe Object est ..........Si deux objets ne sont pas égaux égaux ( ) alors que rien ne garantit que leur hashCode sera le même, le hashCode peut être/ne pas être égal ... peut/peut ne pas retourner vrai.Exemple:

    String str1 = "FB";
    String str2 = "Ea";
    System.out.println(str1.equals(str2));// false
    System.out.println(str1.hashCode() == str2.hashCode()); // true
2
Manish Kumar

// Vous pouvez exécuter le code ci-dessous avec -Xmx2100m et obtenir plusieurs résultats, suffisamment pour remplir votre console.

`

import Java.util.HashMap;

public class TestHashCollision {
        public static void main(String[] args) {
        final String TEXT = "was stored earlier had the same hash as";
        HashMap<Integer,String> hs=new HashMap<>();
        long t1=System.currentTimeMillis();
        long t2=System.currentTimeMillis();
        for(long l=0;l<Long.MAX_VALUE;l++) {
            String key="d"+l;
            if(hs.containsKey(key.hashCode())) {
                System.out.println("'"+hs.get(key.hashCode())+"' "+TEXT+" '"+key+"'");//System.exit(0);
            } else {
                hs.put(key.hashCode(),key);
            }
            t2=System.currentTimeMillis();
            if(t2-t1>10000) {
                t1=System.currentTimeMillis();
                System.out.println("10 seconds gone! size is:"+hs.size());
            }
        }
        System.out.println("Done"); 
    }
}

`

0

Oui (pas seulement en Java, cela s’applique à n’importe quel langage), il peut produire le même code de hachage pour différentes chaînes. Je me souviens d'une règle enseignée par mon professeur, il pourrait être utile ici - 

Deux mêmes chaînes/valeur doivent avoir le même hashcode, mais l'inverse n'est pas vrai. 

exemple en python

>>> hash('same-string')
-5833666992484370527
>>> hash('same-string')
-5833666992484370527

Il est possible qu'une autre chaîne puisse correspondre au même code de hachage. Nous ne pouvons donc pas obtenir la clé à l'aide du code de hachage. 

La raison pour laquelle deux chaînes différentes ont le même code de hachage est due à la collision.  enter image description here

0
ajayramesh