Ordre des éléments dans un HashMap diffèrent lorsque le même programme est exécuté dans JVM5 vs JVM6

StackOverflow https://stackoverflow.com/questions/1879897

  •  18-09-2019
  •  | 
  •  

Question

I ai une application qui affiche une collection d'objets en rangées, un objet = une rangée. Les objets sont stockés dans une table de hachage. L'ordre des lignes ne modifie pas la fonctionnalité de l'application (c'est pourquoi un HashMap a été utilisé à la place d'une collection triables).

Cependant, je l'ai remarqué que la même application fonctionne différemment lorsqu'il est exécuté en utilisant deux versions différentes de la machine virtuelle Java. L'application est compilé en utilisant JDK 5, et peut être exécuté en utilisant soit Java 5 ou 6 Java temps d'exécution, sans aucune différence fonctionnelle.

L'objet en question

Était-ce utile?

La solution

Les détails de mise en œuvre de HashMap peuvent changer et changent. Très probablement cette méthode privée package fait (ce qui est de JDK 1.6.0_16):

/**
 * Applies a supplemental hash function to a given hashCode, which
 * defends against poor quality hash functions.  This is critical
 * because HashMap uses power-of-two length hash tables, that
 * otherwise encounter collisions for hashCodes that do not differ
 * in lower bits. Note: Null keys always map to hash 0, thus index 0.
 */
static int hash(int h) {
    // This function ensures that hashCodes that differ only by
    // constant multiples at each bit position have a bounded
    // number of collisions (approximately 8 at default load factor).
    h ^= (h >>> 20) ^ (h >>> 12);
    return h ^ (h >>> 7) ^ (h >>> 4);
}

Pour référence, l'analogue en 1.5.0_06 est JDK:

/**
 * Returns a hash value for the specified object.  In addition to 
 * the object's own hashCode, this method applies a "supplemental
 * hash function," which defends against poor quality hash functions.
 * This is critical because HashMap uses power-of two length 
 * hash tables.<p>
 *
 * The shift distances in this function were chosen as the result
 * of an automated search over the entire four-dimensional search space.
 */
static int hash(Object x) {
    int h = x.hashCode();

    h += ~(h << 9);
    h ^=  (h >>> 14);
    h +=  (h << 4);
    h ^=  (h >>> 10);
    return h;
}

Autres conseils

Probablement parce qu'un Map n'est pas défini pour avoir un ordre d'itération particulière; l'ordre dans lequel les éléments sont de retour est susceptible d'être un artefact de sa mise en œuvre interne et n'a pas besoin de rester cohérent.

Si la mise en œuvre est mise à jour entre Java 5 et 6 (en particulier pour des raisons de performance), il n'y a aucun avantage ou obligation de Sun pour vous assurer que l'ordre d'itération reste constante entre les deux.

EDIT : Je viens de trouver un extrait intéressant dans l'un des premiers Java 6 versions (malheureusement je ne suis pas sûr de la version exacte mais il est apparemment HashMap 1,68 de Juin 2006):

 /**
  * Whether to prefer the old supplemental hash function, for
  * compatibility with broken applications that rely on the
  * internal hashing order.
  *
  * Set to true only by hotspot when invoked via
  * -XX:+UseNewHashFunction or -XX:+AggressiveOpts
  */
 private static final boolean useNewHash;
 static { useNewHash = false; }

 private static int oldHash(int h) {
     h += ~(h << 9);
     h ^= (h >>> 14);
     h += (h << 4);
     h ^= (h >>> 10);
     return h;
 }

 private static int newHash(int h) {
     // This function ensures that hashCodes that differ only by
     // constant multiples at each bit position have a bounded
     // number of collisions (approximately 8 at default load factor).
     h ^= (h >>> 20) ^ (h >>> 12);
     return h ^ (h >>> 7) ^ (h >>> 4);
 }

Il semble donc que, malgré mes affirmations ci-dessus, Sun a effectivement examiné la cohérence de l'ordre d'itération -. À un moment donné plus tard ce code a probablement été abandonné et le nouvel ordre a le définitif

HashMap est pas marié à une commande particulière, mais la mise en œuvre de la carte de LinkedHashMap doit préserver l'ordre.

scroll top