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?
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?
I navigate to HashSet#iterator
:
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().