List、Set和Map的简单理解

集合类比较多,记忆起来容易弄混


先来一张结构图:

List和Set都是接口并都继承了Collection接口,所以它俩都属于单列集合。
List的子类最常见的有ArrayList类,LinkedList类和Vector类。
Set的子类最常见的有HashSet类,TreeSet类和LinkedHashSet类。

Map类也是如图所示就不一一列出了。


List、Set和Map的简单理解


List类为有存储顺序,可重复集合类。

因为List类是接口只有一堆抽象方法,所以这里就拿ArrayList来看。

下图为java ArrayList源代码中的部分截图。

ArrayList是数组实现的有序可重复集合

最常用的add()方法中将范类E传递给了elementData[size++],而elementData是ArrayList定义的不可序列化的私有成员变量Obejcet类数组,根据size的值也能找到对应的元素,所以简单理解ArrayList实现靠的是数组应该是可以的。

至于这个ensureCapacityInternal()方法是从字面也是也能理解出确保插入元素的时候数组有足够的空间能放。


List、Set和Map的简单理解

List、Set和Map的简单理解

在new了一个ArrayList类后add一个元素后

List、Set和Map的简单理解

执行ensureCapacityInternal()

List、Set和Map的简单理解

接着又将size+1传给了ensureExplicitCapacity()

List、Set和Map的简单理解

如果传进来的值大于数组的长度将会执行grow(),简单来说过程就是一个创建一个是1.5倍原数组大小的数组,将原数组的值复制一遍后再把elementData指向的目标变成新建的数组。

List、Set和Map的简单理解


再来看看LinkedList

LinkedList为List的实现类,也是有序可重复集合,靠的是链表的方式。

下图中可以看出该类拥有两个Node类对象 first和last,这两个便是链表的节点。有了这两个成员变量就可以直接对LinkedList的头部和尾部进行设置。

List、Set和Map的简单理解

这里的Node是LinkedList的静态内部类,从构造方法里可以看出,每个Node都有一个范类对象item负责保存自己的值,还记录了上一个节点和下一个节点的地址。

List、Set和Map的简单理解

在执行add方法时,调用linkLast方法

List、Set和Map的简单理解

在linkLast方法里,将LinkedList的成员变量last节点也就是尾节点设置成新节点的上一个,把add的值传给新节点,把成员变量list指向的目标变成刚刚创建的新节点,这样尾节点就变成了刚创建的新节点了,如果是第一次创建l==null就会成立,首节点的声明first就也会指向新节点,同时父类抽象类里的modCount也进行了++,负责记录长度。

List、Set和Map的简单理解


Set类为无序不重复集合

Set类也是个抽象类,比较有名的是HashSet()

HashSet()类虽然是Set的实现类,但是实现靠的还是Map的实现类HashMap。

创建HashSet()对象时会生成一个常量不可序列化对象HashMap,之后的操作都是对他进行的。

List、Set和Map的简单理解

在add方法里,实际上是将add的参数当做键值给了map,让map调用put方法传递参数,values则为一个新的Object。

List、Set和Map的简单理解

List、Set和Map的简单理解

既然Set类实际上是靠Map类来实现功能的,那就直接看Map类。


Map类为键值集合

键值集合就是一个key对应一个values值且成对出现。

HashMap是无序的(只是说不是你插入时的顺序);

LinkedHashMap是有序的(按你插入的顺序);

TreeMap 是按key排序的;

HashMap 类基本上等同于 Hashtable, 区别仅仅在于: HashMap 不是同步的,并且运行 null 值.。


在HashMap的成员变量里有下图三个静态常量:默认容积,最大容积,默认载入因子。在实例化的时候会用到它们。

List、Set和Map的简单理解

当直接new HashMap()时还是会执行它的有参构造方法,传递的值就是上图中的两个成员变量

这里无非就是对Map的一些设置,因为new HashMap()没有参数所以参数值都是按照上面的静态常量了,而载入因子和初始容积会一起影响Map的大小。

List、Set和Map的简单理解

List、Set和Map的简单理解

table为HashMap的一个Entry成员变量

为当第一次put一对参数时,这个table一定会和EMPTY_TABLE相等,接着执行inflateTable(),里面放的是默认容积参数。

inflateTable()里大致流程是将默认容积参数进行一个调整后乘以载入因子获得一个新值,然后将新值作为参数new一个Entry数组!所以Map里存取数据靠的是Entry数组

List、Set和Map的简单理解

List、Set和Map的简单理解


根据下图可以看出Entry是Map的静态内部类,该类实现了hashcode()方法,这个是实现不重复的重要方法,还有一些get方法来返回对应的values值。

两个范类都是他的成员变量,第一个范类K就是键值,而且还是常量,第二个范类V是对应的值。

而且还有记录下一个Entry类的声明,这就解释了为什么迭代器可以知道下一个参数的地址。

List、Set和Map的简单理解List、Set和Map的简单理解

第一次执行inflateTable后,计算key参数的哈希值和索引值,进入循环,将HashMap生成的、存取数据的Entry数组的地址传给e,对Key值的哈希值进行是否相等的判断,如果有一个和已经添加过的Key值相等的话就直接返回oldValue

如果键值哈希值都不一样并且调用equals也不相等,就执行addEntry,放入key的哈希值,key值和索引值,并将自己的父类里的modCount++进行长度记录。

List、Set和Map的简单理解


总结:

List为有序可重复集合。有序是指由数组实现,所有可以直接定位到某个数组的值。

   可重复是指数组里的参数各不影响,只要是Object就添加进去。

Set本质上也是Map,只不过是个Values值全部是Object对象的Map类。

它是无序集合,无序值指的是,存放元素的是Entry对象,添加数据实际上是计算索引值并存放到table里,获取值时根据这个table的索引值来获取。

它是不可重复集合,因为只有Key值,添加时会进入循环依次计算已经添加过的Key值的哈希值和equals方法判断相等,有一个相等就不能添加进去,从而实现了不可重复。

Map和以上Set的总结大体上一致,只不过是多了个values值。