java自学笔记——HashMap源码初探

java自学笔记——HashMap源码初探

源码

关于下列代码,Debug追源码

/**
 * @author Lspero
 * @version 1.0
 */
@SuppressWarnings("all")
public class HashMapSourse_ {
    public static void main(String[] args) {
        HashMap map = new HashMap();
        map.put("java", 10);
        map.put("php", 10);
        map.put("java", 20);
    }
}

源码如下

		1.执行构造器 new HashMap()
          初始化加载因子 loadfactor = 0.75
          HashMapNode[] table =  null;
          
        2.执行put,调用hash方法,计算key的hash值
          public V put(K key, V value) {
              return putVal(hash(key), key, value, false, true);
          }

          //计算传入对象的Hash值
          static final int hash(Object key) {
              int h;
              return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
          }
          
         3.执行putVal,加入对象
          final V putVal(int hash, K key, V value, boolean onlyIfAbsent, boolean evict) {
              Node<K,V>[] tab; Node<K,V> p; int n, i;//辅助变量
              
              //如果table数组为null ,或 length = 0 , 就扩容到16
              if ((tab = table) == null || (n = tab.length) == 0)
                  n = (tab = resize()).length;
                  
              //取出hash值对应的table的索引位置Node
              //如果为空就直接把加入的K-V创建成Node,加入该位置
              if ((p = tab[i = (n - 1) & hash]) == null)
                  tab[i] = newNode(hash, key, value, null); //e 没有赋值,为空
              else {
                  Node<K,V> e; K k;//辅助变量
                  
                  //如果该table表索引位置key的hash值与新key的hash值相同 并且 
                  //满足现有结点的key与添加的key为同一对象 或 equals返回真,就不加入新结点
                  //p = tab[i = (n - 1) & hash] 根据索引值找到的目标结点
                  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) {//死循环
                      
                         //如果整个链表没有值相同的,就加到该链表的最后
                         //此时 e 为null,链表最后一个的next
                          if ((e = p.next) == null) {
                              p.next = newNode(hash, key, value, null);
                              //判断当前链表个数是否到达8个,有8个就进行treeifyBin(tab, hash)树化
                              if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                                  //树化
                                  treeifyBin(tab, hash);
                              break;
                          }
                          
                          //如果在循环过程发现有相同的,就break,只是替换value
                          if (e.hash == hash &&
                              ((k = e.key) == key || (key != null && key.equals(k))))
                              break;
                              
                          p = e;
                      }
                }
                
                //e不为null,就进行值的替换
                if (e != null) { // existing mapping for key
                    V oldValue = e.value;
                    if (!onlyIfAbsent || oldValue == null)
                        e.value = value;
                    afterNodeAccess(e);
                    return oldValue;
                }
        }
        
        ++modCount;//每增加一个Node,就size++
        if (++size > threshold) //如果大于临界值,就扩容
            resize();
        afterNodeInsertion(evict);
        return null;
    }

    4.关于树化
    //如果table表为空或大小<64,就暂时不树化,而是进行扩容
        final void treeifyBin(Node<K,V>[] tab, int hash) {
            int n, index; Node<K,V> e;
            if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)
                resize();
         }

Hashtable

与HashMap相比主要是线程安全

  1. 底层有数组 Hashtable$Entry[] 初始化为11
  2. 临界值threshold 8 = 11 * 0.75
  3. 扩容 按照扩容机制 *2+1 扩容
  4. 执行 addEntry(hash, key, value, index); 添加K-V 封装到Entry
import java.util.Hashtable;

/**
 * @author Lspero
 * @version 1.0
 */
public class HashTableExerise_ {
    public static void main(String[] args) {
        /*
        1.底层有数组 Hashtable$Entry[] 初始化为11
        2.临界值threshold 8 = 11 * 0.75
        3.扩容 按照扩容机制扩容
        4.执行 addEntry(hash, key, value, index); 添加K-V 封装到Entry
        5.当 if (count >= threshold) {
                // Rehash the table if the threshold is exceeded
                rehash();//扩容
        6.按照 int newCapacity = (oldCapacity << 1) + 1; *2+1 扩容
         */
        Hashtable hashtable = new Hashtable();
        for (int i = 0; i < 8; i++) {
            hashtable.put(i, "hello");
        }
        hashtable.put(20, "he");
    }
}

Properties

通常用于从 xxx.properties 文件中,加载数据到Properties类对象,并进行读取和修改

  1. 继承Hashtable并实现Map接口,K-V不能为null
  2. 使用方式和Hashtable类似
  3. xxx.properties 文件通常作为配置文件,在IO流中使用
import java.util.Properties;

/**
 * @author Lspero
 * @version 1.0
 */
public class Properties_ {
    public static void main(String[] args) {
        /*
        1.继承Hashtable并实现Map接口,K-V不能为null
        2.使用方式和Hashtable类似
        3.通常用于从 xxx.properties 文件中,加载数据到Properties类对象,并进行读取和修改
        4.xxx.properties 文件通常作为配置文件,在IO流中使用
         */
        Properties properties = new Properties();
        properties.put("jhon", 100);
        properties.put("lucy", 100);
        properties.put("lic", 100);
        properties.put("lic", 88);

        System.out.println("properties=" + properties);

        System.out.println(properties.get("lic"));
        properties.remove("lic");
        System.out.println("properties=" + properties);
        properties.put("jhon", "约翰");
        System.out.println("properties=" + properties);
        System.out.println(properties.getProperty("jhon"));
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值