Map
接口
哈希表就是一种以键
-
值
(key-indexed)
存储数据的结构,只要输入待查找的值即
key
,即可查找到其对应的值。
哈希的思路很简单,如果所有的键
hashCode
都是整数,那么就可以使用一个简单的无序数组来实现:将键作为索
引,值即为其对应的值,这样就可以快速访问任意键的值。
Map
提供了一组键值的映射
Entry
。其中存储的每个数据对象都有一个相应的键
key
,键决定了值对象在
Map
中的存
储位置。键应该是唯一的,不允许重复,每个
key
只能映射一个
value
。
Map
接口中常见方法
Object put(Objectkey,Object value)
:用来存放一个键
-
值对
Map
中
,
如果出现
key
值冲突则后盖前。允许
key
值和
value
值为
null
,但是
key
值为
null
只能有一个,
value
值为
null
没有个数限制。事实上如果
key
已经存在则
返回被覆盖的
value
值,如果
key
不存在则返回
null
size():int
用于获取集合中的元素个数
Object remove(Object key)
:根据
key(
键
)
,移除键
-
值对,并将值返回
Object get(Object key)
:根据
key(
键
)
取得对应的值
,
如果
key
值不存在则返回为
null
boolean containsKey(Object key)
:判断
Map
中是否存在某键
key
boolean containsValue(Object value):
判断
Map
中是否存在某值
value
void clear()
:清空当前
Map
中的元素
map
提供了
3
种访问视图
public Set keySet()
:返回所有的键
key
,并使用
Set
容器存放,获取
key
值后就可以通过
get
方法获取
key
对应的值
value
public Collection values()
:返回所有的值
Value
,并使用
Collection
存放
public Set entrySet()
:返回一个实现
Map.Entry
接口的元素
Set
Map
实现类
HashMap
、
TreeMap
、
LinkedHashMap
、
Hashtable
等
HashMap
HashMap()
采用所有的默认配置值,其中的参数值有
initialCapacity:int
初始化容积,默认值
DEFAULT_INITIAL_CAPACITY=16
,第
2
个参数是
loadFactor:flfloat
用于设置加载因子,取值范围为
0-1
之间,默认值
为
DEFAULT_LOAD_FACTOR
,值越大则存储数据越多,
hash
冲突的概率越高;值越小则越浪费空间,但是
hash
冲
突的概率越低。为了减少
hash
冲突,引入了加载因子,加载因子表示容器中最多存储百分子多少的数据。例如默认
容器为
16
,默认加载因子为
0.75
,则表示最多存储
16*0.75
个元素,如果大于这个值则需要进行扩容
HashMap
的存储结构
每个
Node[]
数组中的元素被称一个桶
bucket
,一个桶对应一个
hash
映射的值,例如
0
,
1
等,可能会出现不同的
key
,但是
hash
映射的位置相同
,
例如
16
、
32
等,这采用链表结构存储
hash
映射值相同的所有数据
(JDK8
在单个链表
长度大于阈值时自动转换为红黑树
,
删除节点使某单个链表节点数小于阈值时会自动从红黑树退化为链表结构
)
相关参数
:
capacity
:当前数组容量,始终保持
2^n
,可以扩容,扩容后数组大小为当前的
2
倍。
loadFactor
:负载因子,默认为
0.75
。
threshold
:扩容的阈值,等于
capacity * loadFactor
HashMap
底层采用的是
Entry
数组和链表实现。
Map
主要用于存储键
key
值
value
对,根据键得到值,因此键不允许重复,但允许值重复
HashMap
是一个最常用的
Map
,它根据键的
HashCode
值存储数据,根据键可以直接获取它的值,具有很快
的访问速度
HashMap
最多只允许一条记录的键为
null
;允许多条记录的值为
null
HashMap
不支持线程的同步,即任一时刻可以有多个线程同时写
HashMap
;可能会导致数据的不一致,会出现环
形链。如果需要同步,可以用
Collections
的
synchronizedMap
方法使
HashMap
具有同步的能力
Java7
中使用
Entry
来代表每个
HashMap
中的数据节点,
Java8
中使用
Node
,基本没有区别,都是
key
,
value
,
hash
和
next
这四个属性,不过,
Node
只能用于链表的情况,红黑树的情况需要使用
TreeNode
。
TREEIFY_THRESHOLD
为
8
如果新插入的值是链表中的第
9
个会触发下面的
treeifyBin(
树化操作,就是将单向链转
换为红黑树
)
,也就是将链表转换为红黑树。
JDK8+
插入数据到链表的最后面,
Java7
是插入到链表的最前面
HashMap
存储键值对,
key
不能重复(
keySet():Set
),但是
value
可以重复
(values():Collection)
;
key
的实现就是
HashSet
;
value
对应着放;允许
null
的键或值;
HashMap
是线程不安全的,在多线程环境下,使用
Hashmap
进行
put
操作会引起死循环,导致
CPU
利用率接近
100%
,所以在并发情况下不能使用
HashMap
。