ArrayListMultimap类的继承关系如下图所示:

Guava ArrayListMultimap

List
Multimap
是一个接口,继承自
Multimap
接口。ListMultimap接口为所有继实现自ListMultimap的子类定义了一些共有的方法签名。ListMultimap接口并没有定义自己特有的方法签名,里面所有的方法都是重写了Multimap接口中的声明,只是将Multimap接口中返回Collection类型的函数修改成返回List类型。比如Multimap接口中get函数的函数原型为Collection

get(@Nullable K key);而ListMultimap接口则变成了List

get(@Nullable K key);这是因为Multimap接口为多个实现类定义了其子类必须实现的方法,由于其子类(TreeMultimap、
ArrayListMultimap)的实现不一样,而Multimap接口又定义了它们共有的方法,所以里面的函数原型大多数的返回类型为Collection,我们知道List、Set都继承自Collection。ListMultimap接口的这种设计符合
《里氏替换法则》

AbstractListMultimap继承自
AbstractMapBasedMultimap类,并实现了ListMultimap接口。AbstractListMultimap类中主要实现了ListMultimap接口里面的方法。同ListMultimap接口类似,AbstractListMultimap类将
AbstractMapBasedMultimap类中返回Collection类型的函数修改成返回List类型。里面很多的实现都是调用了AbstractMapBasedMultimap类中相应函数的实现,仅仅简单的将返回Collection类型函数修改为List类型。

AbstractMapBasedMultimap类的介绍请参见
《Guava学习之AbstractMapBasedMultimap》

ArrayListMultimap类是Multimap接口的ArrayList方法实现的类,在前面的《Guava学习之AbstractMapBasedMultimap》文章中我们谈到了Multimap接口的几种实现,其中就有以ArrayList实现的。

这里说的以ArrayList实现或者TreeSet实现是指key所对应的value存放方式。详细介绍请看
《Guava学习之AbstractMapBasedMultimap》

ArrayListMultimap类主要有三个构造函数,实现如下:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
private
ArrayListMultimap() {
  
super
(
new
HashMap<K, Collection<V>>());
  
expectedValuesPerKey = DEFAULT_VALUES_PER_KEY;
}
 
private
ArrayListMultimap(
int
expectedKeys,
int
expectedValuesPerKey) {
  
super
(Maps.<K, Collection<V>>newHashMapWithExpectedSize(expectedKeys));
  
checkArgument(expectedValuesPerKey >=
0
);
  
this
.expectedValuesPerKey = expectedValuesPerKey;
}
 
private
ArrayListMultimap(Multimap<?
extends
K, ?
extends
V> multimap) {
  
this
(multimap.keySet().size(),
      
(multimap
instanceof
ArrayListMultimap) ?
          
((ArrayListMultimap<?, ?>) multimap).expectedValuesPerKey :
          
DEFAULT_VALUES_PER_KEY);
  
putAll(multimap);
}

第一个构造函数其键存储是用HashMap来实现的;而value的存储是用ArrayList来实现的,如下所示:

1
2
3
@Override
List<V> createCollection() {
  
return
new
ArrayList<V>(expectedValuesPerKey);
}

其中的expectedValuesPerKey 表示预期一个key会有多少个value,这里直接将DEFAULT_VALUES_PER_KEY赋值给expectedValuesPerKey,通过源码我们可以得到DEFAULT_VALUES_PER_KEY=3。
第二个构造函数有两个参数int expectedKeys, int expectedValuesPerKey,其中expectedKeys表示用户预期有多少个key,expectedValuesPerKey表示用户预期一个key会有多少个value。如果你大致知道你的程序会有多少个key和value,建议用这个构造函数,这样可以省去由于空间不足而需要重新分配空间而带来的额外开销。
第三个构造函数是将另一个multimap中的所有键值元素直接复制到我们新建的multimap中,这个方式比较简单,和第一个构造函数类似,我们都不需要知道会有多少个key和value。
从上面的构造函数我们可以看出,这三个构造函数都是以private修饰的,这说明了我们不能直接调用ArrayListMultimap类的构造函数。由于此原因,ArrayListMultimap类为我们带来了以下几个用于创建ArrayListMultimap对象的静态方法:

01
02
03
04
05
06
07
08
09
10
11
12
13
public
static
<K, V> ArrayListMultimap<K, V> create() {
  
return
new
ArrayListMultimap<K, V>();
}
 
public
static
<K, V> ArrayListMultimap<K, V> create(
    
int
expectedKeys,
int
expectedValuesPerKey) {
  
return
new
ArrayListMultimap<K, V>(expectedKeys, expectedValuesPerKey);
}
 
public
static
<K, V> ArrayListMultimap<K, V> create(
    
Multimap<?
extends
K, ?
extends
V> multimap) {
  
return
new
ArrayListMultimap<K, V>(multimap);
}

可以看出,上面三个静态函数分别对应地调用ArrayListMultimap的三个构造函数,含义我就不说了,很简单。
如果你的ArrayListMultimap对象的value经过了各种的删除、添加操作,这时候可能会导致许多的value空间都没有用到,我们可以用下面的函数来将没用的空间去掉,使得各个key对应value空间的大小等于其对应的value个数:

01
02
03
04
05
06
07
08
09
10
11
public
void
trimToSize() {
  
for
(Collection<V> collection : backingMap().values()) {
    
ArrayList<V> arrayList = (ArrayList<V>) collection;
    
arrayList.trimToSize();
  
}
}
backingMap()函数的实现: 
Map<K, Collection<V>> backingMap() {
  
return
map;
}
private
transient
Map<K, Collection<V>> map;

里面的map就是构造函数super(new HashMap<k ,="" collection

>())中的HashMap。

注意,这里说的是value所用的空间,没说是key所用的空间。

(完)

[置顶] Guava学习之ArrayListMultimap的更多相关文章

  1. [置顶] Guava学习之Multimap

    相信大家对Java中的Map类及其之类有大致的了解,Map类是以键值对的形式来存储元素(Key->Value),但是熟悉Map的人都知道,Map中存储的Key是唯一的.什么意思呢?就是假如我们有 ...

  2. [置顶] Guava学习之Splitter

    Splitter:在Guava官方的解释为:Extracts non-overlapping substrings from an input string, typically by recogni ...

  3. [置顶] Guava学习之Iterators

    Iterators类提供了返回Iterator类型的对象或者对Iterator类型对象操作的方法.除了特别的说明,Iterators类中所有的方法都在Iterables类中有相应的基于Iterable ...

  4. [置顶] Guava学习之Lists

    Lists类主要提供了对List类的子类构造以及操作的静态方法.在Lists类中支持构造ArrayList.LinkedList以及newCopyOnWriteArrayList对象的方法.其中提供了 ...

  5. [置顶] Guava学习之Immutable集合

    Immutable中文意思就是不可变.那为什么需要构建一个不可变的对象?原因有以下几点: 在并发程序中,使用Immutable既保证线程安全性,也大大增强了并发时的效率(跟并发锁方式相比).尤其当一个 ...

  6. [置顶] Docker学习总结(7)——云端基于Docker的微服务与持续交付实践

    本文根据[2016 全球运维大会•深圳站]现场演讲嘉宾分享内容整理而成 讲师简介 易立 毕业于北京大学,获得学士学位和硕士学位:目前负责阿里云容器技术相关的产品的研发工作. 加入阿里之前,曾在IBM中 ...

  7. [置顶] 小白学习KM算法详细总结--附上模板题hdu2255

    KM算法是基于匈牙利算法求最大或最小权值的完备匹配 关于KM不知道看了多久,每次都不能完全理解,今天花了很久的时间做个总结,归纳以及结合别人的总结给出自己的理解,希望自己以后来看能一目了然,也希望对刚 ...

  8. [置顶] iOS学习笔记47——图片异步加载之EGOImageLoading

    上次在<iOS学习笔记46——图片异步加载之SDWebImage>中介绍过一个开源的图片异步加载库,今天来介绍另外一个功能类似的EGOImageLoading,看名字知道,之前的一篇学习笔 ...

  9. [置顶] Android学习系列-Android中解析xml(7)

    Android学习系列-Android中解析xml(7) 一,概述 1,一个是DOM,它是生成一个树,有了树以后你搜索.查找都可以做. 2,另一种是基于流的,就是解析器从头到尾解析一遍xml文件.   ...

随机推荐

  1. android ImageView scaleType属性(转)

    使用ImageView时经常会用到scaleType属性,如: 1 2 3 4 5 6 7 8 9 <ImageView   android:layout_width="50dp&qu ...

  2. Android Studio下打jar包

    在我们使用Eclipse时,我们常常使用的第三方类库文件大多都是jar包形式,用起来很方便.但是jar包只能打包class文件,对于Android UI类库而言,我们常常需要打包资源文件,对于界面不多 ...

  3. jquery ajax 提交表单(file && input)

    用到的插件 jquery.js jquery.form.js[http://malsup.github.io/jquery.form.js] 提交页面 <form enctype="m ...

  4. dedecms调用所有顶级栏目最新文章的实现方法

    做dedecms的模板,我们会遇到各种各样的调用问题,dedecms列表页调用所有顶级栏目文章列表的方法如下所述: 在文章页面经常使用的是 {dede:arclist orderby='pubdate ...

  5. 第二部分面向对像基础第五章Strng类中方法的使用

    package com.java.oop.day2; import java.util.Calendar; import java.util.Formatter; import java.util.L ...

  6. scrolView

    禁止UIScrollView垂直方向滚动,只允许水平方向滚动 scrollview.contentSize =  CGSizeMake(长度, 0); 禁止UIScrollView水平方向滚动,只允许 ...

  7. 小波 mallat 算法

    算法要求:输入序列是大于滤波器长度的偶数列 确实可以通过编程的手段使算法适合所有的情况,但本文章的目的是展示mallat算法的过程,所以就一切从简了 // Mallat.cpp : Defines t ...

  8. 学习用CMake来编写Qt程序

    最近开始学习CMake,因为项目需求需要用到Qt,自带的qmake会出现许多问题(比如文件修改之后有时候qmake不会侦测到不会重新编译,需要手动去编译等),于是开始尝试使用CMake来编写Qt程序, ...

  9. centos账户的uid和gid

    修改/etc/passwd和/etc/group文件的UID和GID为0,可以获得root权限,不过不推荐~ UID和GID Linux系统如何区别不同的用户呢?可以很自然地想到,使用不同的用户名应该 ...

  10. Python标准库--os模块

    这个模块包含普遍的操作系统功能.如果你希望你的程序能够与平台无关的话,这个模块是尤为重要的.即它允许一个程序在编写后不需要任何改动,也不会发生任何问题,就可以在Linux和Windows下运行.一个例 ...