在源代码中实现了LinkedHashSet和HashSet的迭代器有不同的行为吗?

时间:2014-04-18 05:45:08

标签: java collections iterator hashset linkedhashset

我调查了LinkedHashSetHashSet个收藏品。

我写了一个小程序:

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+"";
    }
}

输出:

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

当我看到这种行为时,我开始研究集合的源代码。

我注意到LinkedHashSet和HashSet都使用

常见toString()实现 - 来自AbstractCollection

来自iterator()

和常见HashSet

我的代码中LinkedHashSetHashSet的不同输出是什么解释?

Ivan Babanin回答后的更新

对于LinkedHashSetHashSet调用不同的构造函数:

代表LinkedHashSet -

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

代表HashSet -

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

HashMap和 - LinkedHasMap的迭代器(来自HashSet

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

研究keySet()方法:

HashMap

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

LinkedHashMap无法特别实现keySet方法并使用HashMap实现。

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()返回HashMapLinkedHashMap的相同类型,因此会调用相同的newEntryIterator()方法。

这是错误的陈述吗?

用于EJP更新

我导航到HashSet#iterator

enter image description here

enter image description here

enter image description here

2 个答案:

答案 0 :(得分:0)

LinkedHashSet 维护插入顺序,但 HashSet 不会。引自 LinkedHashSet 的javadoc:

  

Set接口的哈希表和链表实现,具有可预测的迭代顺序。此实现与HashSet的不同之处在于它维护了一个贯穿其所有条目的双向链表。此链接列表定义迭代排序,即元素插入集合(插入顺序)的顺序。

LinkedHashSet 的任何构造函数都会调用 HashSet 的超级构造函数:

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

LinkedHashMap Map 接口的哈希表和链表实现,具有可预测的迭代顺序。

答案 1 :(得分:0)

你没有深入挖掘。

  • HashSet.iterator()返回map.keySet().iterator()
  • map.keySet()返回HashMap.KeySet
  • HashMap.KeySet.iterator()来电[HashMap.this.]newKeyIterator()
  • LinkedHashMap会覆盖newKeyIterator().