Where in the source code is it implemented that iterators from LinkedHashSet and HashSet have different behaviour?

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

Question

I investigate LinkedHashSet and HashSet collections.

I wrote small program:

public class LHSTest {
    public static void main(String[] args){
        output(test(new LinkedHashSet()));
        System.out.println("=========");
        output(test(new HashSet()));

    }
    public static HashSet<MyClass> test(HashSet hashSet){
        hashSet.add(new MyClass(1));
        hashSet.add(new MyClass(2));
        hashSet.add(new MyClass(3));
        hashSet.add(new MyClass(4));
        hashSet.add(new MyClass(5));
         return  hashSet;
    }
    public static void output(HashSet hashSet){
        for(Iterator iterator = hashSet.iterator();iterator.hasNext();){
            System.out.println(iterator.next());
        }
    }
}

class MyClass{
    int a;
    MyClass(int a){
        this.a =a;
    }
    public int hashCode(){
        return 15-a;
    }
    public String toString()   {
        return  a+"";
    }
}

output:

1
2
3
4
5
=========
5
4
3
2
1

When I saw this behaviour I began research source code of collections.

I noticed that both LinkedHashSet and HashSet use

common toString() realization - from AbstractCollection

and common iterator() from HashSet

What were explain the different output for LinkedHashSet and HashSet in my code?

Update after Ivan Babanin answer

For LinkedHashSet and HashSet invoke different constructors:

for LinkedHashSet -

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<E,Object>(initialCapacity, loadFactor);
}

for HashSet -

 public HashSet() {
    map = new HashMap<E,Object>();
 }

iterator for both HashMap and -LinkedHasMap (from HashSet)

public Iterator<E> iterator() {
    return map.keySet().iterator();
 }

Research keySet() method:

HashMap:

public Set<K> keySet() {
        Set<K> ks = keySet;
        return (ks != null ? ks : (keySet = new KeySet()));
}

LinkedHashMap cannot especial realization for keySet method and uses HashMap realization.

map.keySet().iterator() is :

public class HashMap<K,V>    extends AbstractMap<K,V>    implements Map<K,V>, Cloneable,      Serializable{
     ...
    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
          public Iterator<Map.Entry<K,V>> iterator() {
               return newEntryIterator();
          }
            ...
    }
     ...
}

map.keySet() returns same type for HashMap and LinkedHashMap therefore invoke same newEntryIterator() method.

Is it wrong statement?

for EJP update

I navigate to HashSet#iterator:

enter image description here

enter image description here

enter image description here

Was it helpful?

Solution

You didn't dig very deep.

  • HashSet.iterator() returns map.keySet().iterator()
  • map.keySet() returns a HashMap.KeySet
  • HashMap.KeySet.iterator() calls [HashMap.this.]newKeyIterator()
  • LinkedHashMap overrides newKeyIterator().

OTHER TIPS

LinkedHashSet maintains insertion order, but HashSet doesn't. Quote from LinkedHashSet's javadoc:

Hash table and linked list implementation of the Set interface, with predictable iteration order. This implementation differs from HashSet in that it maintains a doubly-linked list running through all of its entries. This linked list defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order).

Any constructor of LinkedHashSet invokes super constructor of HashSet:

HashSet(int initialCapacity, float loadFactor, boolean dummy) {
    map = new LinkedHashMap<>(initialCapacity, loadFactor);
}

And LinkedHashMap is hash table and linked list implementation of the Map interface, with predictable iteration order.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top