把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数组之后,创建迭代器之前,集合可能发生了增删操作,所以
- 数组遍历结束之前,迭代器中没下一个元素了,则利用Arrays.copyOf截取数组返回。
- 数组遍历结束之后,迭代器中还有下一个元素,则需要给数组扩容,直到能容纳迭代器中的所有元素为止。
如果创建迭代器后,集合发生增删操作,迭代器的next()会抛出ConcurrentModificationException。