把HashMap的values放到list中

2022-01-30  本文已影响0人  M_lear

这么做

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。

上一篇下一篇

猜你喜欢

热点阅读