Map类

Map

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

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

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

public interface Map

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

public static void main(String[] args) {
    // Map常用方法
    // 创建Map
    Map<String, String> 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转换成一个集合
import java.util.Collections;
import java.util.HashMap;
import java.util.Set;

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

    //创建Map
    Map<String, String> 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<Map.Entry<String, String>> entries = map.entrySet();

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

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

    //获取所有的键
    Set
<String> 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
<String> 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()

源码

成员变量

// 默认加载因子
static final float DEFAULT_LOAD_FACTOR = 0.75f;
// 加载因子
final float loadFactor;
// 扩容的阈值
int threshold;
// 底层的数组
transient Node<K, V>[] 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方法

final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    // tab 底层数组   p是数组中的一个结点
    Node<K, V>[] tab;
    Node<K, V> 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<K, V> 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<K, V>) 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;
}
final Node<K, V>[] resize() {
    // 旧的数组
    Node<K, V>[] 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<K, V>[] newTab = (Node<K, V>[]) new Node[newCap];
    table = newTab;
    // 把结点从旧的数组中移动到新的数组中
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            Node<K, V> 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<K, V>) e).split(this, newTab, j, oldCap);
                else { // preserve order
                    Node<K, V> loHead = null, loTail = null;
                    Node<K, V> hiHead = null, hiTail = null;
                    Node<K, V> 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
小恐龙
花!
上一篇
下一篇