Map类

# Map

Map称之为映射,也称之为双列集合。Map中包含key(键)和value(值),key不能重复,一个key对应一个value.

key和value称之为键值对,键值对也是一个类,是Map.Entry

一个映射由多个键值对组成。

### public interface Map

K 键值 (键值不能重复)
V Value ( value 可以重复)

“`java
public static void main(String[] args) {
// Map常用方法
// 创建Map
Map map = new HashMap<>();
// 添加数据
map.put(“郭德纲”, “于谦”);
map.put(“赵本山”, “范伟”);
map.put(“虹猫”, “蓝兔”);
map.put(“熊大”, “熊二”);
map.put(“灰太狼”, “喜羊羊”);
// String put = map.put(“赵本山”, “高秀敏”);
// System.out.println(put);
map.put(“林志玲”, “范伟”);
// 根据key获取value
String s = map.get(“赵本山”);
System.out.println(s);
System.out.println(map);
}
“`

– 常用方法
– map.put(K,V) 添加数据
– map.get() 根据Key获取Value
– map.clear() 清空映射
– map.containsKey() 判断是否包含键值
– map.containsValue() 判断是否包含value
– map.entrySet()
– map.isEmpty() 是否为空
– map.keySet() 获取所有的键
– map.remove(K) 根据键值删除value
– map.remove(K,V) 根据键值和Value删除
– map.size() 返回键值对数量
– map.values() 把所有的value转换成一个集合

“`java
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;

public static void main(String[] args) {
//Map常用方法

//创建Map
Map map = new HashMap<>();

//添加数据

// 添加数据
map.put(“郭德纲”, “于谦”);
map.put(“赵本山”, “范伟”);
map.put(“虹猫”, “蓝兔”);
map.put(“熊大”, “熊二”);
map.put(“灰太狼”, “喜羊羊”);
map.put(“林志玲”, “范伟”);

//根据Key值获取value
String s = map.get(“赵本山”);
System.out.println(s);

//清空映射
map.clear();

//判断是否包含某一个key
boolean containsKey = map.containsKey(“林志玲”);
System.out.println(containsKey);

//判断是否包含某一个value
System.out.println(map.containsValue(“宋丹丹”));
Set> entries = map.entrySet();

// lambda表达式
entries.forEach(entry -> System.out.println(entry.getKey() + entry.getValue()));

//判断map是否为空
boolean empty = map.isEmpty();
System.out.println(empty);

//获取所有的键
Set strings = map.KeySet();
System.out.println(strings);

//根据key删除键值对,返回value
String remove = map.remove(“林志玲”);
System.out.println(remove);

//删除指定的key和value,返回删除成功或者失败
boolean remove1 = map.remove(“灰太狼”, “红太狼”);
System.out.println(remove1);
System.out.println(map.size());

Collection values = map.values;
System.out.println(values);
System.out.println(map);
}
“`

# HashMap

HashMap是哈希表的一个实现,是无需的,Key是唯一的,并且Key和Value都可以是null,元素位置可能发生改变,是线程不安全的映射

## 构造方法

– HashMap()
是默认初始容量16,默认加载因子为0.75,构造一个空HashMap(只当的初始容量(如果不是2的n次方,底层会通过算法变为2的n次方形式)
– HashMap(int initialCapacity)
使用指定的初始容量(如果不是2的n次方,底层会通过算法变成2的n次方的形式)和指定加载因子构造一个空 HashMap
– HashMap()

## 源码

### 成员变量

“`java
// 默认加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 加载因子
final float loadFactor;
// 扩容的阈值
int threshold;
// 底层的数组
transient Node[] table;
// 初始化容量
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16 // 实际元素个数 transient int size; // 扭转成红黑数的值 static final int TREEIFY_THRESHOLD = 8; ``` ### 源码 - 当创建HashMap时,会把加载因子赋值为0.75 - 当第一次put时,会创建一个长度为16的Node类型的数组,默认的阈值是12,吧数据包装成结点放入数组中 - 如果key相同,hash值肯定相同,会用新值覆盖旧值,并返回旧值 - 如果key不同,但是hash值相同,会在对应的桶(bucket)上的位置进行一个个比较,知道链表节点的next为null为止,然后把结点放到链表的最后 - 当链表长度大于8,并且数组长度大于等于64时,链表会扭转成红黑树,如果数组长度<64,会进行一次扩容 - 扩容是原来的容量翻倍,如果原来桶上的是链表,那么扩容后要么在原来的位置,要么是原来位置 + 原来数组的长度 - HashMap的初始化容量一定是2的n次方的形式 - 当扩容时,如果桶上是红黑树,当长度 <=6 时,会把红黑树扭转成链表 注意点:使用HashMap时,key一般不要是自定义的对象。如果真的要使用,建议重写equals和hashCode方法 ```java final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) { // tab 底层数组 p是数组中的一个结点 Node[] tab;
Node p;
// n 数组的长度
// i 是元素要放的数组的索引
int n, i;
// 首次调用put时,或执行resize方法,创建长度为16的数组
if ((tab = table) == null || (n = tab.length) == 0)
n = (tab = resize()).length;
// (n – 1) & hash 计算元素的索引
if ((p = tab[i = (n – 1) & hash]) == null)
// 如果索引处没有元素,直接创建结点放到索引处
tab[i] = newNode(hash, key, value, null);
else {
Node e;
K k;
// 比较key是否相同
if (p.hash == hash &&
((k = p.key) == key || (key != null && key.equals(k))))
e = p;
else if (p instanceof TreeNode)// 判断是否是红黑树
e = ((TreeNode) p).putTreeVal(this, tab, hash, key, value);
else {
for (int binCount = 0; ; ++binCount) {
// 链表中的结点一个个比较
if ((e = p.next) == null) {
// 在链表的最后创建结点
p.next = newNode(hash, key, value, null);
// 是否要扭转成红黑树
if (binCount >= TREEIFY_THRESHOLD – 1) // -1 for 1st
treeifyBin(tab, hash);
break;
}
// 比较key是否相同
if (e.hash == hash &&
((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
}
}
// key相同的情况下,用新的value替换旧的value
if (e != null) { // existing mapping for key
V oldValue = e.value;
if (!onlyIfAbsent || oldValue == null)
e.value = value;
afterNodeAccess(e);
return oldValue;
}
}
++modCount;
// 判断是否需要扩容
if (++size > threshold)
resize();
afterNodeInsertion(evict);
return null;
}
“`

“`java
final Node[] resize() {
// 旧的数组
Node[] oldTab = table;
// 旧的数组的长度
int oldCap = (oldTab == null) ? 0 : oldTab.length;
// 旧的阈值
int oldThr = threshold;
// 新的数组长度和新的阈值
int newCap, newThr = 0;
// 旧的数组长度 > 0 说明要扩容
if (oldCap > 0) {
if (oldCap >= MAXIMUM_CAPACITY) {
threshold = Integer.MAX_VALUE;
return oldTab;
}
// 计算扩容之后数组的长度和新的阈值
else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY && oldCap >= DEFAULT_INITIAL_CAPACITY)
newThr = oldThr << 1; // double threshold } else if (oldThr > 0) // initial capacity was placed in threshold
newCap = oldThr;
else { // zero initial threshold signifies using defaults
// 设置默认的新数组长度和阈值
newCap = DEFAULT_INITIAL_CAPACITY;
newThr = (int) (DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
}
if (newThr == 0) {
float ft = (float) newCap * loadFactor;
newThr = (newCap < MAXIMUM_CAPACITY && ft < (float) MAXIMUM_CAPACITY ? (int) ft : Integer.MAX_VALUE); } // 设置扩容的阈值 threshold = newThr; // 创建数组 @SuppressWarnings({"rawtypes", "unchecked"}) Node[] newTab = (Node[]) new Node[newCap];
table = newTab;
// 把结点从旧的数组中移动到新的数组中
if (oldTab != null) {
for (int j = 0; j < oldCap; ++j) { Node e;
if ((e = oldTab[j]) != null) {
oldTab[j] = null;
if (e.next == null)
newTab[e.hash & (newCap – 1)] = e;
else if (e instanceof TreeNode)
((TreeNode) e).split(this, newTab, j, oldCap);
else { // preserve order
Node loHead = null, loTail = null;
Node hiHead = null, hiTail = null;
Node next;
do {
next = e.next;
if ((e.hash & oldCap) == 0) {
if (loTail == null)
loHead = e;
else
loTail.next = e;
loTail = e;
} else {
if (hiTail == null)
hiHead = e;
else
hiTail.next = e;
hiTail = e;
}
} while ((e = next) != null);
if (loTail != null) {
loTail.next = null;
newTab[j] = loHead;
}
if (hiTail != null) {
hiTail.next = null;
newTab[j + oldCap] = hiHead;
}
}
}
}
}
return newTab;
}
“`

# Hashtable

– Hashtable的key和value不能是null,线程安全。
– 默认的初始容量是11,加载因子是0.75
– 默认扩容是先翻倍再加一
– 指定的容量给多少就是多少

| 实现类 | 底层数据结构 | key/value为null | 线程是否安全 |
| ———————- | ———————— | —————————– | ———— |
| HashMap | 数组 + 单向链表 + 红黑树 | 都可以是null | 不安全 |
| LinkedHashMap | 数组 + 双向链表 + 红黑树 | 都可以是null | 不安全 |
| TreeMap | 红黑树 | key不能是null,value可以是null | 不安全 |
| Hashtable | 哈希表 | 都不能是null | 安全 |
| ConcurrentHashMap | 哈希表 | 都不能是null | 安全 |

暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇