You are right that you only need to maintain a singly linked list to keep track of insertion order. But in order to efficiently maintain a singly linked list, you actually need a doubly linked list.
Consider three entries in order
A ---> B ---> C
Suppose you remove B
. Obviously A
should now point to C
. But unless you know the entry before B
you cannot efficiently say which entry should now point to C
. To fix this, you need entries to point in both directions.
---> --->
A B C
<--- <---
This way, when you remove B
you can just look at the entries before and after B
(A
and C
) and update so that A
and C
point to each other.
The reason LinkedHashMap
maintains insertion order while HashMap
doesn't, despite the fact that all but 4 methods are inherited, is that it's very cleverly written. Most implementation-specific operations are members of HashMap.Entry
, not HashMap
. LinkedHashMap
has a private static
class LinkedHashMap.Entry
which extends the static
class HashMap.Entry
of HashMap
. When you call put
or remove
, for example, the code for LinkedHashMap
can be the same as the code for HashMap
because it is the entries themselves that keep track of before and after information. As an example, here is the code in full for LinkedHashMap.Entry.remove()
that I was explaining above
private void remove() {
before.after = after;
after.before = before;
}