(Map集合)HashMap子类

HashMap子类

HashMap是Map接口之中最为常见的一个子类,该类的主要特点是无序存储,通过Java的文档首先来观察一下HashMap子类的定义形式:

public class HashMap<K,​V>
extends AbstractMap<K,​V>
implements Map<K,​V>, Cloneable, Serializable

该类的定义继承形式符合之前的集合定义形式,依然提供有抽象类并且依然需要重复实现Map接口。

 范例:观察Map集合的使用

import java.util.HashMap;
import java.util.Map;

public class MapDemo {

    public static void main(String[] args) {

        Map<String,Integer> hashMap = new HashMap<String,Integer>();
        hashMap.put("one",1);
        hashMap.put("one",100); //重复数据
        hashMap.put("two",2);
        hashMap.put(null,0);    //key为空
        hashMap.put("zero",null);   //value为空

        //根据key找value
        System.out.println(hashMap.get("one"));
        System.out.println(hashMap.get(null));
        System.out.println(hashMap.get("ten")); //不存在的key

    }

}

100
0
null

以上的操作形式为Map集合使用的最标准的处理形式,通过代码可以发现,通过HashMap实例化的Map接口里面可以发现:

  • key或者value可以保存null的数据;
  • 相同的key名字重复保存,之前的key会被后面保存的key替换。

但是对于Map接口中提供的put()方法本身是提供有返回值的,那么这个返回值指的是在重复key的情况下返回旧的value;

//put方法
public V put​(K key, V value)

范例:观察put()方法的返回值

import java.util.HashMap;
import java.util.Map;

public class MapDemo {

    public static void main(String[] args) {

        Map<String,Integer> hashMap = new HashMap<String,Integer>();
        System.out.println(hashMap.put("one",1));   //key不重复
        System.out.println(hashMap.put("one",100)); //key重复

    }

}

null
1

清楚了HashMap基本功能之后,下面研究一下HashMap之中的源代码:

//无参构造
public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
    }

//里面的参数
static final float DEFAULT_LOAD_FACTOR = 0.75f;

//put()方法
 public V put(K key, V value) {
        return putVal(hash(key), key, value, false, true);    //调用了putVal,对key进行hash处理(生成独一无二的hash码代表它)
    }

//putVal方法,提供了Node的节点类进行数据的保存
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
        if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
        else {
            Node<K,V> e; K k;
            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;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;
                    p = e;
                }
            }
            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();        //这里调用了resize()方法,可以进行容量的扩充
        afterNodeInsertion(ev    ict);
        return null;
    }

面试题:在进行HashMap的put()操作时如何实现容量扩充?

  • 初始化容量:static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; 在HashMap类里面有一个“DEFAULT_INITIAL_CAPACITY ”常量作为初始化的容量配置,这个常量的容量配置为16个元素,默认可以保存最大内容是16。
  • 当保存的内容的容量超过了一个阈值(static final float DEFAULT_LOAD_FACTOR = 0.75f;),相当于“容量*阈值”(如果容量是100,那么阈值就是75),当容量超过了结果时就会进行容量的扩充。
  • 在进行扩充的时候HashMap采用的是成倍的扩充模式,即每一次扩充两倍的容量。

面试题:请解释HashMap的工作原理

  • 在HashMap之中进行数据存储的依然是利用了Node类完成的,那么这种情况下就证明可以使用的数据结构只有两种:链表(时间复杂度:“O(n)”)、二叉树(时间复杂度:O(logn)“”);
  • 从JDK1.8开始,HashMap的实现发生了改变,因为其要适应于大数据时代的海量数据问题,所以对于其存储发生了变化,并且在HashMap类的内部提供了一个重要的常量:( static final int TREEIFY_THRESHOLD = 8;)在使用HashMap进行数据保存的时候如果保存的数据个数没有超过阈值8,那么会按照链表的形式存储,如果超过了则将链表转为红黑树以实现树的平衡,并且利用左旋右旋保证数据的查询性能。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值