java hashmap源码学习一 属性、构造方法

java8中HashMap的主要结构由数组,单链表和红黑树组成。
HashMap有一个属性load_factor(加载因子),它控制hashmap在容量达到多满时(加载因子*容量)要进行扩容,默认为0.75。加载因子大可以节省空间,但会增加查询成本。
它的主要属性:

// 默认容量为16
static final int DEFAULT_INITIAL_CAPACITY = 1 << 4;

// 最大容量
static final int MAXIMUM_CAPACITY = 1 << 30;

//默认加载因子0.75
static final float DEFAULT_LOAD_FACTOR = 0.75f;

//当链表中的节点个数大于这个值时,会变成红黑树。默认值为8
static final int TREEIFY_THRESHOLD = 8;

//当进行resize()时,假如树中节点小于这个值时,用链表代替树,默认值为6
static final int UNTREEIFY_THRESHOLD = 6;

//当链表要被树化时,hashmap的最小容量,否则会被resize()。这个值至少是TREEIFY_THRESHOLD的四倍
static final int MIN_TREEIFY_CAPACITY = 64;

HashMap最底层的结构,每个节点有hash值,key, value, next(用来产生单链表)属性,getKey, getValue, toString, hashCode, setValue, equals方法,equals(Object o)方法要判断keyvalue都相同才返回true

static class Node<K, V> implements Map.Entry<K, V>{
    final int hash;
    final K key;
    V value;
    Node<K, V> next;

    Node(int hash, K key, V value, Node<K, V> next){
    this.hash = hash;
    this.key = key;
    this.value = value;
    this.next = next;
    }

    ...

    public final int hashCode() {
        return Objects.hashCode(key) ^ Objects.hashCode(value);
    }

    ...
}

根据key拿到对应hash值的方法:

static final int hash(Object key){
    int h;
    return (key == 0) ? 0 : (h = key.hasCode())^(h>>>16);
}

数组结构:

transient Node<K, V>[] table;

根据所给的capacity返回大于这个capacity的最小的二次幂size,具体解释见http://blog.csdn.net/fan2012huan/article/details/51097331

为什么容量一定要2的n次幂?
因为在之后的put()get()方法中,会通过(size-1)&hash(对应给定key的hash值)来找到索引然后再进行操作,这个算式是固定,用这个算式可以确保索引在数组范围之内。当size是2的n次幂时,size-1就是奇数,这样它的最后一位是1,所以最后算出来的索引值最后一位可能为0,也可能为1,否则的话索引的最后一个值只能是0,这样会导致只能利用一半的空间。


static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}

四个构造函数:

//指定容量和加载因子的构造函数
public HashMap(int initialCapacity, float loadFactor){
    //检查输入是否合法
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " + initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " + loadFactor);

    this loadFactor = loadFactor;
    this threshold = tableSizeFor(initialCapacity);
    //本来threshold应该等于size*loadFactor表示结构该扩容的阈值,不过,在构造方法中,并没有对table进行初始化,所以threshold也会在后面的方法中重新赋值
}


//指定容量的构造函数
public HashMap(int initialCapacity){
    this(initialCapacity, DEFAULT_LOAD_FACTOR);

//无参构造函数
public HashMap(){
    this.loadFactor = DEFAULT_LOAD_FACTOR;
}

//直接放入一个Map,具体见
http://blog.sina.com.cn/s/blog_9b6eb6f90102wvft.html

public HashMap(Map<? extends K, ? extends V> m) {
    this.loadFactor = DEFAULT_LOAD_FACTOR;
    putMapEntries(m, false);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值