`

java --HashTable学习

 
阅读更多

 今天在家无事,闲来看看JDK源码,就从HashTable看起了.

 

键值都不能为空。
为了能从hashtable中存储或者获取值,作为key的对象必须实现hashCode和equals方法。
一个hashtable实例有两个参数会影响它的效率:
   1、initial Capacity  (初始容量) 默认11
   2、load facotr (加载因子):是对哈希表在其容量自动增加之前可以达到多满的一个尺度 默认0.75f
二、变量

(1)Entry[] table:the hash table data
(2)int count:the total number of entries in the hash table.
(3)threshold: the table is rehashed when its size exceeds this threshold.
  threshold=(int)(capacity * loadFactor).
(4)float loadFactor
(5)int modCount=0 :The mumber of times this Hashtable has been structurally modified.


三、方法


(1)构造方法中:
  初始化initialCapacity
  初始化loadFactor
  初始化table=new Entry[initialCapacity]
  初始化 threshold=(int)(capacity * loadFactor).


(2) public synchronized int size():返回count的值


(3) public synchronized boolean isEmpty() :count是0返回true,否则返回false.


 (4)
 

   public synchronized boolean contains(Object value) {
 if (value == null) {
     throw new NullPointerException();
 }
       //数组,数组中的每一个元素又是一个单向链表(Entry:HashTable的内部类)
 Entry tab[] = table;
 for (int i = tab.length ; i-- > 0 ;) {
     for (Entry<K,V> e = tab[i] ; e != null ; e = e.next) {
  if (e.value.equals(value)) {
      return true;
  }
     }
 }
 return false;
    }

 

(5)第一步:得到当前key的hashCode
     第二步:通过hashCode得到在数组中的位置index
     第三步:根据index得到单向链表,从表头开始查找,是否存在当前元素。

 public synchronized V get(Object key) {
 Entry tab[] = table;
      //得到hash值,通过hash值找到在数据中的位置,再在对应的单向链表中对应的值。
 int hash = key.hashCode();
 int index = (hash & 0x7FFFFFFF) % tab.length;
 for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
     if ((e.hash == hash) && e.key.equals(key)) {
  return e.value;
     }
 }
 return null;
    }

 
(6)增加数组的容量,重新计算hashCode,重新进行存储,大致分为以下几步:
  第一步:增加容量至:oldCapacity * 2 + 1
  第二步:循环数组,循环每个数组元素对应的单向链表,从头开始,重新计算hashCode,重新进行存储,

 protected void rehash() {
 int oldCapacity = table.length;
 Entry[] oldMap = table;

 int newCapacity = oldCapacity * 2 + 1;
 Entry[] newMap = new Entry[newCapacity];

 modCount++;
 threshold = (int)(newCapacity * loadFactor);
 table = newMap;

 for (int i = oldCapacity ; i-- > 0 ;) {
     for (Entry<K,V> old = oldMap[i] ; old != null ; ) {
  Entry<K,V> e = old;
  old = old.next;

  int index = (e.hash & 0x7FFFFFFF) % newCapacity;
  e.next = newMap[index];
  newMap[index] = e;
     }
 }
    }

 
(7) put方法,大致分为三步:
  第一步:确保value不为空
  第二步:循环数据,进一步循环链表,确保此key在当前hashTable中不存在,如果存在,则更换为新值。
  第三步:modCount+1,如果当前的count >= threshold,则调用rehash()方法扩充数据容量,重新计算hashCode,重新进行存储。
  第四步:在单向链表的表头插入当前entry.
 

 public synchronized V put(K key, V value) {
 // Make sure the value is not null
 if (value == null) {
     throw new NullPointerException();
 }

 // Makes sure the key is not already in the hashtable.
 Entry tab[] = table;
 int hash = key.hashCode();
 int index = (hash & 0x7FFFFFFF) % tab.length;
 for (Entry<K,V> e = tab[index] ; e != null ; e = e.next) {
     if ((e.hash == hash) && e.key.equals(key)) {
  V old = e.value;
  e.value = value;
  return old;
     }
 }

 modCount++;
 if (count >= threshold) {
     // Rehash the table if the threshold is exceeded
     rehash();

            tab = table;
            index = (hash & 0x7FFFFFFF) % tab.length;
 } 

 // Creates the new entry.
 Entry<K,V> e = tab[index];
 tab[index] = new Entry<K,V>(hash, key, value, e);
 count++;
 return null;
    }

 

总结:1、hashTable是线程安全的,键值不能为空。
      2、第一层存储结构是一个数组,数组中的每个元素又是一个单向链表。
      3、插入时,通过key的hashCode得到数组中存储位置,在单向链表的表头插入。
      4、插入时要检查当前数据中的元素个数,是否大于等于threshold,如果大于等于threshold,则会调用rehash()方法,建立一个新的数组,其大小为oldCapacity * 2 + 1,
然后把旧的数组中的每个元素取出来,重新计算hashCode、在数组中的位置、在链表中的位置。
      5、因为threshold=初始容量*加载因子,所以rehash方法的调用与初始容量、加载因子有很大的关系,而rehash方法是hashtable中最费时间的方法,这就是为什么都说

hashtable实例的初始容量、加载因子最影响他的效率。
      6、默认加载因子(0.75)在时间和空间成本上寻求一种折衷。加载因子过高虽然减少了空间开销,但同时也增加了查找某个条目的时间。
      7、初始容量主要控制空间消耗与执行 rehash 操作所需要的时间损耗之间的平衡。如果初始容量大于 Hashtable 所包含的最大条目数除以加载因子,即最大条目<初始容量

*加载因子,则永远 不会发生 rehash 操作。但是,将初始容量设置太高可能会浪费空间。

分享到:
评论

相关推荐

    Java集合专题总结:HashMap 和 HashTable 源码学习和面试总结

    Java集合专题总结:HashMap 和 HashTable 源码学习和面试总结

    使用JavaScript数组模拟Java的Hashtable集合

    因为,JavaScript的数组非常特殊,而且如果你能够理解它,那么对于我们学习JSON对象语法就非常容易理解了--因为JSON就是一个数组--我们也可以把它看成一个Hashtable集合对象!本人认为,理解JavaScript的数组是学习...

    (超赞)JAVA精华之--深入JAVA API

    1.5 J2SE学习中的30个基本概念 1.6 Java线程 1.7 Java 5.0多线程编程 1.8 Java Socket编程 1.9 Java的内存泄漏 1.10 抽象类与接口的区别 1.11 Java变量类型间的相互转换 2 JAVA与WEB 2.1 JMX规范 2.1.1 JMX概述 ...

    Java 集合学习指南 - v1.1.pdf

    Java的集合类总结,包括HashMap、HashSet、HashTable、LinkedHashMap、LinkedHashSet、ArrayList、LinkedList、ConcurrentHashMap的实现原理,很详实,面试的话可以认真看看

    【Java面试+Java学习指南】 一份涵盖大部分Java程序员所需要掌握的核心知识

    Java集合详解4:HashMap和HashTable Java集合详解5:深入理解LinkedHashMap和LRU缓存 Java集合详解6:TreeMap和红黑树 Java集合详解7:HashSet,TreeSet与LinkedHashSet Java集合详解8:Java集合类细节精讲 JavaWeb

    java8源码-java-start::seedling::seedling::seedling:学习Java语法过程中的一些案例

    java8 源码 目录 Java 基础 容器 并发 JVM I/O Java 8 编程规范 网络 操作系统 Linux相关 数据结构与算法 数据结构 算法 数据库 MySQL Redis 系统设计 常用框架 Spring ZooKeeper 权限认证 设计模式 数据通信 网站...

    实战应用Java算法分析与设计-1算计概述与抽象数据类型

    通过本课程的学习,学员可以掌握以下技术点:线性结构与顺序表、单向链表、循环链表、栈的基本概念、链式堆栈、中缀表达式、队列、链式队列、串、MyString、Brute-Force算法、MySet类实现、矩阵类、递归算法、哈夫曼...

    java8源码-JavaRobot:Java学习笔记,JavaLearningNote

    学习笔记(持续更新中) 所有文章均同步发布到微信公众号【JavaRobot】,关注微信公众号,及时得到文章推送,谢谢支持。 说明:如无特别说明,所有代码都基于JDK8 JavaSE(Java基础) Java Core 关键字 synchronized...

    JAVA SE学习精华集锦

    1.5 J2SE学习中的30个基本概念 58 1.6 Java线程 60 1.7 Java 5.0多线程编程 65 1.8 Java Socket编程 80 1.9 Java的内存泄漏 85 1.10 抽象类与接口的区别 86 1.11 Java变量类型间的相互转换 87 2 JAVA与WEB 87 2.1 ...

    java summary(java笔记)

    学习java的一些笔记和个人总结 9、Collection 和 Collections的区别。  Collection是集合类的上级接口,继承与他的接口主要有Set 和List.。Collections是针对集合类的一个帮助类,他提供一系列静态方法实现对各种...

    实战应用Java算法分析与设计-3图的概念以及图的邻接矩阵类实现

    通过本课程的学习,学员可以掌握以下技术点:线性结构与顺序表、单向链表、循环链表、栈的基本概念、链式堆栈、中缀表达式、队列、链式队列、串、MyString、Brute-Force算法、MySet类实现、矩阵类、递归算法、哈夫曼...

    Java工程师面试复习指南

    【Java工程师面试复习指南】本仓库架构大部分Java工程师所需要掌握的核心知识,整合了互联网上的很多优质Java技术文章,力求打造为最完整最实用的...Java集合详解:HashMap和HashTable Java集合详解:深入理解LinkedHas

    动力节点_Java基础视频教程139_HashTable与HashMap的异同点

    动力节点的Java课程适合绝对零基础的观看,教程中讲解了Java开发环境搭建、Java的基础语法、Java的面向对象。每一个知识点都讲解的非常细腻,由浅入深。适合非计算机专业,想转行做Java开发的朋友,或者想让Java基础...

    javajdk源码学习-JavaSourceLearn:JDK源码学习

    java jdk源码学习 JavaSourceLearn 版本号 版本 corretto-1.8.0_275 方式 逐步阅读源码添加注释、notes文件夹添加笔记 计划学习任务计划 标题为包名,后面序号为优先级1-4,...Hashtable 1 HashSet 1 LinkedHashMa

    java面试笔试资料包括JAVA基础核心知识点深度学习Spring面试题等资料合集.zip

    java面试笔试资料包括JAVA基础核心知识点深度学习Spring面试题等资料合集: JAVA核心知识点整理-282页 Java与哈希算法.docx Java中Lambda表达式的使用.docx JAVA多线程之线程间的通信方式.docx Java注解详解.docx ...

    java7hashmap源码-learning-record:学习轨迹记录

    学习轨迹记录 10月1号 7月18号 基础算法:反转单向链表 7月16号 7月11号 7月9号 复习 : HashTable和HashMap的区别详解 LeetCode 27. 删除元素(Remove Element) 7月8号 7月5号 复习hashMap concurrentHashmap ...

    01java基础-集合知识点详解.xlsx

    就是一些通用java集合知识点整理,ArrayList LinkedList,HashMap,HashTable ,ConcurrentHashMap,HashSet,LinkedHashSet类通过线程安全否: 底层: 初始值: 扩容 : 区别(对比优势) 图解

    张孝祥Java就业培训教程.pdf

    本书不仅全面的介绍了Java语言本身,最重要还交会读者去掌握编程思想,找到编程感觉,而不是死记硬背语言本身,书中涉及到的应用问题分析,远远超了一个Java程序员在学习和应用Java过程中所有可能碰到的问题。...

    JAVA_Thinking in Java(中文版 由yyc,spirit整理).chm

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

    java 编程入门思考

    2. Java的学习 3. 目标 4. 联机文档 5. 章节 6. 练习 7. 多媒体CD-ROM 8. 源代码 9. 编码样式 10. Java版本 11. 课程和培训 12. 错误 13. 封面设计 14. 致谢 第1章 对象入门 1.1 抽象的进步 1.2 对象的接口 1.3 ...

Global site tag (gtag.js) - Google Analytics