简体   繁体   中英

How to understand the hashCode function of java.util.Hashtable in the source codes of JDK

As is said in the documentary, "This code abuses the loadFactor field to do double-duty as a hashCode in progress flag, so as not to worsen the space performance.A negative load factor indicates that hash code computation is in progress." How to understand this paragraph?

public synchronized int hashCode() {
    /*
     * This code detects the recursion caused by computing the hash code
     * of a self-referential hash table and prevents the stack overflow
     * that would otherwise result.  This allows certain 1.1-era
     * applets with self-referential hash tables to work.  This code
     * abuses the loadFactor field to do double-duty as a hashCode
     * in progress flag, so as not to worsen the space performance.
     * A negative load factor indicates that hash code computation is
     * in progress.
     */
    int h = 0;
    if (count == 0 || loadFactor < 0)
        return h;  // Returns zero

    loadFactor = -loadFactor;  // Mark hashCode computation in progress
    Entry[] tab = table;
    for (int i = 0; i < tab.length; i++)
        for (Entry e = tab[i]; e != null; e = e.next)
            h += e.key.hashCode() ^ e.value.hashCode();
    loadFactor = -loadFactor;  // Mark hashCode computation complete

return h;

The purpose of the use of the load factor as an in-progress check is to ensure that the code won't get stuck in an infinite loop if there is a circular chain of references back to the hash table itself. For example, imagine a hash table of type Hashtable<String,Hashtable> , ie a map from strings to other hash tables. Then, an entry in the table might contain a reference to the same hash table itself; or, it might point to another hash table of the same type, which then points back to the same table. Because the hashing code recursively computes the hash codes of the keys and values and then combines them to produce the final hash code, it will get stuck in an infinite loop if it doesn't detect circular references (cycles in the graph).

When the code encounters a circular reference, it will notice this because the load factor will be negative, indicating that the hash table has already been encountered. In that case, it will break the loop by returning 0 rather than recursing further.

I have done a lot of work on XEmacs, which had similar hashing code in its Lisp interpreter. It used a different trick: it had a recursion depth value which was passed into the equivalent of the hashCode function and incremented every time the function recursed into another object. If the depth was above a certain amount, it refused to recurse further. This is less brittle than Java's trick but isn't possible in Java because the hashCode function's signature is fixed and doesn't have a recursion depth argument in it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM