Reading values from Hashtable is showing the inverse of natural order

时间:2018-03-25 18:45:50

标签: java collections

Why when executing the following code the HashMap and Hashtable have different behaviour for reading values since both of them are based on the same hashcode method (Integer hashcode) for storing value and the only difference between those two structures is : thread safety and allowing null key and value:

public static void main(String[] args) {
        Hashtable<Integer, String> hashtable = new Hashtable<>();
        hashtable.put(4,"4");
        hashtable.put(2,"2");
        hashtable.put(3,"3");
        hashtable.put(8,"8");
        System.out.println(hashtable.values());// [8, 4, 3, 2]

        HashMap<Integer, String> hashMap = new HashMap<>();
        hashMap.put(4,"4");
        hashMap.put(2,"2");
        hashMap.put(3,"3");
        hashMap.put(8,"8");
        System.out.println(hashMap.values());// [2, 3, 4, 8]
    }

1 个答案:

答案 0 :(得分:2)

NOTE: This is not documentated behaviour and could be different in another JVM version/update or JVM implementation. Having said that it's unlikely to be different as there might be programs which rely on this behaviour and there is unlikely to be a good reason to change the default implementation.


The reason it appears in natural order for HashMap in the Oracle/OpenJDK is that for small hashCode() values, the keys happens to not be randomly arranged in the underlying array. For non-negative values less than the capacity which don't get "agitated" by the simple bit re-arranging function, the value of the hashCode is also the index in the array.

The iterator for HashMap proceeds from the start of the array to the end.

In the case of Hashtable, the layout is the same, the difference being that values() iterates from the end of the array to the start.

    public boolean hasMoreElements() {
        Entry<?,?> e = entry;
        int i = index;
        Entry<?,?>[] t = table;
        /* Use locals for faster loop iteration */
        while (e == null && i > 0) {
            e = t[--i];
        }
        entry = e;
        index = i;
        return e != null;
    }

I suspect this is a micro-optimisation where the iterator doesn't need to be compared to the size, but rather 0

In short, it's not thread safety, allowing null nor the initial capacity. (The capacity only matters in terms of the range of values this will work for)