美文网首页
把HashMap的values放到list中

把HashMap的values放到list中

作者: M_lear | 来源:发表于2022-01-30 14:42 被阅读0次

    这么做

    Map<String, List<Integer>> map = new HashMap<>();
    map.put("Alice", new ArrayList<>(Arrays.asList(1, 2, 3)));
    map.put("Mark", new ArrayList<>(Arrays.asList(3, 2, 1)));
    

    搞法一

    List<List<Integer>> list = new ArrayList<>(map.values());
    

    搞法二

    List<List<Integer>> list = map.values().stream().collect(Collectors.toList());
    

    看看搞法一底层是怎么做的

    看看ArrayList的这个构造函数:

        public ArrayList(Collection<? extends E> c) {
            elementData = c.toArray();
            if ((size = elementData.length) != 0) {
                // c.toArray might (incorrectly) not return Object[] (see 6260652)
                if (elementData.getClass() != Object[].class)
                    elementData = Arrays.copyOf(elementData, size, Object[].class);
            } else {
                // replace with empty array.
                this.elementData = EMPTY_ELEMENTDATA;
            }
        }
    

    ArrayList通过调用map.values()的toArray()方法为elementData赋值。

    看看HashMap的values():

        public Collection<V> values() {
            Collection<V> vs = values;
            if (vs == null) {
                vs = new Values();
                values = vs;
            }
            return vs;
        }
    

    返回值是Collection类型。
    Values是HashMap的内部类,查看其实现:

        final class Values extends AbstractCollection<V> {
            public final int size()                 { return size; }
            public final void clear()               { HashMap.this.clear(); }
            public final Iterator<V> iterator()     { return new ValueIterator(); }
            public final boolean contains(Object o) { return containsValue(o); }
            public final Spliterator<V> spliterator() {
                return new ValueSpliterator<>(HashMap.this, 0, -1, 0, 0);
            }
            public final void forEach(Consumer<? super V> action) {
                Node<K,V>[] tab;
                if (action == null)
                    throw new NullPointerException();
                if (size > 0 && (tab = table) != null) {
                    int mc = modCount;
                    for (int i = 0; i < tab.length; ++i) {
                        for (Node<K,V> e = tab[i]; e != null; e = e.next)
                            action.accept(e.value);
                    }
                    if (modCount != mc)
                        throw new ConcurrentModificationException();
                }
            }
        }
    

    继承自AbstractCollection。
    Values并没有实现toArray(),看来使用的是AbstractCollection的toArray()实现。

    看看AbstractCollection的toArray()实现:

    public abstract class AbstractCollection<E> implements Collection<E> {
        // 省略
    
        public abstract Iterator<E> iterator();
    
        public abstract int size();
    
        public Object[] toArray() {
            // Estimate size of array; be prepared to see more or fewer elements
            Object[] r = new Object[size()];
            Iterator<E> it = iterator();
            for (int i = 0; i < r.length; i++) {
                if (! it.hasNext()) // fewer elements than expected
                    return Arrays.copyOf(r, i);
                r[i] = it.next();
            }
            return it.hasNext() ? finishToArray(r, it) : r;
        }
    
        // 省略
    

    AbstractCollection的toArray()依赖子类定义的迭代器实现,其余方法没贴出来,其实AbstractCollection定义的所有操作几乎都依赖子类定义的迭代器来实现。

    toArray()大致逻辑:
    先是根据size()创建了一个Object数组。
    然后创建一个迭代器,利用迭代器来填充数组值。
    由于创建Object数组之后,创建迭代器之前,集合可能发生了增删操作,所以

    1. 数组遍历结束之前,迭代器中没下一个元素了,则利用Arrays.copyOf截取数组返回。
    2. 数组遍历结束之后,迭代器中还有下一个元素,则需要给数组扩容,直到能容纳迭代器中的所有元素为止。

    如果创建迭代器后,集合发生增删操作,迭代器的next()会抛出ConcurrentModificationException。

    相关文章

      网友评论

          本文标题:把HashMap的values放到list中

          本文链接:https://www.haomeiwen.com/subject/ppuqkrtx.html