java容器框架知识汇总
java容器(集合)框架知识简单汇总
前言:这是我的第一篇个人博客,作为小白的一名,希望有大佬可以看到我的这篇随笔,有不当的地方,请“猛烈的”攻击我,千万不要留情。谢谢!在您看到这篇随笔的时候,若有任何存疑的地方请指出,然后再“猛烈的”攻击我。嘿嘿。
文章结构--围绕:
“两大类别” “三小接口” “多个实现类”
两大类别:
在Java中集合总的分为两种大类,一个是存取单个元素的的集合接口,另一个是存取“键值对”的集合接口,(不懂接口的同学,可以暂时理解为:鑫鑫怪对整个Java集合分了两个大类)
对第一个类来说(存取单个元素的集合接口们)其实我觉得汇总起来就一个玩意儿,Collection接口,我们所用的ArrayList呀、Linklist呀、Vector呀、HashSet呀啥的都是它的后代。
另一个类别呢(存取键值对的集合接口)这也是一个玩意儿,Map接口,同样我们使用的也是他的后代例如HashMap、TreeMap呀这些什么的。
三小接口(其实一点都不小):
前面有说到两大类,现在我们开始展开
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
对于类一:Collection接口就是他梦的开始,接口在Java中是不能被实现,但可以被继承的,所以继承自Collection的两个孩子List和Set接口开始离家出走,出现在了我们视线中。
我们都知道孩子尽管是双胞胎也是有差异的所以对于List和Set这俩来说也是有差别的:
List接口的特点是:不唯一,有序
Set接口的特点是:唯一,无序
咋理解呢?
不唯一:其实呢就是在List接口下的集合他们里面所存的数据是可以重复的,例如一个名为“大帅哥鑫鑫怪”的元素存入这个集合中后,你可以再存一个相同名字元素进去程序不会报错。
有序:顾名思义就是他们的存取的顺序就是有循序的,可以联想一下数据结构数组的样子。
现在我们来细数一下他们一些重要的实现类
List接口下的ArrayList、LinkList、Vector
ArrayList
底层数据结构:
ArrayList的底层数据结构是数组
构造方法:

这里有必要说一下,ArrayList这孩子呢比较不一样,他“一出生”是“空”的,就是啥也没有,那他在什么时候才有呢?在我们第一次调用add方法的时候才会对他进行初始化,初始化的大小是10,说到初始化就要说说什么是扩容了,扩容就是当你集合的容量被用光的时候就会触发ArrayList的扩容机制,他的扩容是0.5倍,即第一次扩容之后的容量大小就是15。具体的关于扩容机制的代码,不展开,感兴趣的童鞋可以查一查百度。
常用方法:
| 返回类型 方法名(参数) | 描述 |
boolean |
将指定的元素追加到此列表的末尾。 |
|
在此列表中的指定位置插入指定的元素。 |
boolean addAll(Collection<? extends E> c) |
按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。 |
void clear() |
从列表中删除所有元素。 |
boolean contains(Object o) |
如果此列表包含指定的元素,则返回 true 。 |
get(int index) |
返回此列表中指定位置的元素。 |
int indexOf(Object o) |
返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。 |
boolean isEmpty() |
如果此列表不包含元素,则返回 true 。
|
remove(int index) |
删除该列表中指定位置的元素。 |
|
从列表中删除指定元素的第一个出现(如果存在)。 |
|
从此列表中删除指定集合中包含的所有元素。
|
|
仅保留此列表中包含在指定集合中的元素。
|
|
用指定的元素替换此列表中指定位置的元素。
|
|
返回此列表中的元素数。
|
|
使用提供的
Comparator对此列表进行排序以比较元素。 |
原谅我是API的搬运工
功能特点:关于AarryList的功能,因为他的数据结构是数组,所以他的查询效率会好一点,但他的增删改的效率不高,因为在计算机在存数组的时候是采用的一段连续的内存对一个数组来说,每个空间都有一个下标,这就是他容易查询的原因,直接通过下标获取元素,但如果进行元素的修改的话,这个过程不展开,简单说就是每次修改的时候相当于开辟一个新的数组然后进行copy,深入了解可以看看他的源码。
Vector
大概说一下不详细展开因为他和ArrayList在同一个父类接口下所以他们的方法很像
但需要注意他们之间的千差万别:
- 他们初始化的位置不同:ArrayLsit是在第一次add方法进行初始化,Vector则是在进行对象创建,构造方法时进行初始化容量同样是10
- ArrayList是线程不安全的但效率搞,Vector则相反:因为Vector的方法都被synchronized修饰,所以他是线程同步的,但这极大的影响了效率
- 发行版本不同:ArrayList是在JDK1.2发布的、Vector则是在JDK1.0发布的
- 扩容倍数不同:ArrayList是每次0.5倍,而Vectorr则是1倍的扩容
LinkList
linkList的父接口与ArrayList一样所以他们常用方法都是一样,这里不继续做API的搬运工了
主要说一下LinkList的数据结构
LinkList的数据结构是链表,与ArrayList不同,所以他的功能方面也有不同。我一直都认同“结构决定功能”的说法。因为他的链式结构,我们在使用LinkList集合时他的修改(增、删、改)的效率会高一些。但查询的效率就会低一些了。因为链表结构的数据在内存中的存储是不连续的,因此每次查找的时候都需要找到“头”然后找下去,但进行修改操作的时候则只需修改“链条”就可以了。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Set接口下的HashSet、TreeSet
前面我们有提到Set接口的特点,不唯一、无序
HashSet
构造方法:

底层数据结构:
方法:
因为Set接口集合List集合的父接口都是Collection所以他们的方法都大同小异
特点:
API文档的表述:
此类实现Set接口,由哈希表(实际为HashMap实例)支持。 对集合的迭代次序不作任何保证; 特别是,它不能保证订单在一段时间内保持不变。 这个类允许null元素。
这个类提供了基本操作(add,remove,contains和size)固定的时间性能,假定哈希函数将分散的桶中正确的元素。 迭代此集合需要与HashSet实例的大小(元素数量)和后台HashMap实例(桶数)的“容量”的总和成比例的时间。 因此,如果迭代性能很重要,不要将初始容量设置得太高(或负载因子太低)是非常重要的。
请注意,此实现不同步。 如果多个线程并发访问哈希集,并且至少有一个线程修改该集合,那么它必须在外部进行同步。 这通常通过在自然地封装集合的一些对象上进行同步来实现。 如果没有这样的对象存在,那么该集合应该使用Collections.synchronizedSet方法“包装”。
总的来说:
HashSet是线程不安全的他的初始容量是16,负载因子为3/4
另外两个知识点:
1.HashSet其实就是HashMap的Key值。
2.当需要在一个HashSet内添加自定义引用变量的时候必须在这个类中重写HashCode()方法和equals()方法。
TreeSet
构造方法

在使用TreeSet的时候需要注意一个最关键的地方,必须编辑比较,可以是外部比较器通过构造方法当作参数传入,也可以在元素内部实现比较接口,实现内部比较器
方法
|
方法类型 方法名 |
描述 |
|
将指定的元素添加到此集合(如果尚未存在)。 |
|
|
Boolean addAll(Collection<? extends E> c) |
将指定集合中的所有元素添加到此集合中。 |
|
返回此集合中最小元素大于或等于给定元素,如果没有此元素,则返回 null 。
|
|
|
Void clear() |
从此集合中删除所有元素。 |
|
Comparator<? super E> comparator() |
返回用于对该集合中的元素进行排序的比较器,或null,如果此集合使用其元素的natural ordering 。 |
|
如果此集合包含指定的元素,则返回 true 。 |
|
|
Boolean isEmpty() |
如果此集合不包含元素,则返回 true 。 |
|
如果存在,则从该集合中删除指定的元素。 |
|
|
Int size() |
返回此集合中的元素数(其基数)。 |
特点
TreeSet的底层数据结构是红黑树,如果需要使用该集合时必须实现比较器(无论是外部比较器还是内部比较器)
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Map接口(存取键值对 Entry(key,value))
两大实现类
HashMap 、TreeMap
HashMap:
关于HashMap本小白觉得可以的话,要深入,特别深入去了解一下原因如下
(都是大佬们告诉我的)
- 面试会问(问的还很详细,设计源码,版本性、结构、扩容、负载因子等)
- 很经典(怎么说呢,在我认为这个知识点,体系比较全)
- 工作中会经常用
所以,对于HashMap这里本小白只是大概总结个人的想法,有问题请大神指出。
构造方法
方法
|
方法类型 方法名 |
描述 |
|
public int size()
|
返回此地图中键值映射的数量。 即返回key的个数
|
|
public boolean isEmpty()
|
如果此地图不包含键值映射,则返回 true 。 判断这个集合是否是空的
|
|
|
返回到指定键所映射的值,或null如果此映射包含该键的映射。 通过key值返回value的值
|
|
public boolean containsKey(Object key)
|
如果此映射包含指定键的映射,则返回 true 。 是否包含~
|
|
V value)
|
将指定的值与此映射中的指定键相关联。 如果地图先前包含了该键的映射,则替换旧值。
相当于List接口中add的作用 |
|
|
从该地图中删除指定键的映射(如果存在)。
|
|
public void clear()
|
从这张地图中删除所有的映射。 此呼叫返回后,地图将为空。
|
|
public boolean containsValue(Object value)
|
如果此地图将一个或多个键映射到指定的值,则返回 true 。
|
|
|
迭代正在进行中修改映射(除了通过迭代器自己的remove操作),迭代的结果是未定义的。 该组支持元件移除,即从映射中相应的映射,经由Iterator.remove,Set.remove,removeAll,retainAll和clear操作。 它不支持add或addAll操作。
|
|
public Collection<V> values()
|
中的迭代正在进行中修改映射(除了通过迭代器自己的remove操作),迭代的结果是未定义的。 该collection支持元素移除,即从映射中相应的映射,经由Iterator.remove,Collection.remove,removeAll,retainAll和clear操作。 它不支持add或addAll操作。
|
|
public boolean remove(Object key, Object value)
|
仅当指定的密钥当前映射到指定的值时删除该条目。
|
底层数据结构
版本8时的数据结构是:数组+链表+红黑树的结构
版本7时的数据结构是:数据+链表
其实他们的底层并不是我这里说的这么简单,还有深层的不展开啦
个人看法:
大概说一下hashmap存储的过程
创建之后,初始容量大小是16,然后进行entry实体的添加,第一步计算key值的哈希值,然后通过一个y=(x)的函数(x是key值得哈希值,y是这个entry实体在集合中存储的位置序号)然后检查这个位置上有没有其他的entry实体,如果没有就添加进去,如果就根据这个格子的链子往后查找,直到没有位置。如果链子的大小超过了8,并且满足格子的数量超过了64则进行红黑树的转化
一、1.7 与1.8的对比
首先是他们的底层数据结构不同,在1.8时hashmap得到底层加入了一个红黑树的数据结构,在“链子”达到8时会自动转成一个红黑树的结构,目的是提高查询的效率,需要注意,当hashmap的长度达到64之后才会进行转化。
插入方式不同:1.7的时候采用的是头插法的形式,这会导致一个问题会有些消耗资源
1.8的时候则采用了尾插法的形式
详细的说:1.7的时候底层采用的是数组+segment+链表的形式(具体各位可以查资料)
1.8的时候是采用的是 数组+红黑树+链表的形式
二、负载因子的到理解
首先负载因子是什么?我的理解就是一个有临界刻度线,然后集合就像是一个水缸,他们一起就是一个有临界刻度线的水缸
负载因子的值:0.75
假设一个hashmap的集合的大小是16那么他实际存的容量是12(16*0.75)如果,超过这个值,就会进行扩容,扩容为原来的两倍是32,至于为什么是0.75而不是其他值,大家可以去查查资料
这里我说结论:这个因子过大就会影响时间效率,过小就会浪费空间。
一个小知识点:负载因子 0.75这是经过大量测试后时间效率和空间利用率上的均衡取值,跟泊松有啥关系。泊松分布是在链表元素在8时候升级为红黑树和红黑树在元素个数为6时候降级链表的解释。

浙公网安备 33010602011771号