`

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 实例 - 遍历 HashTable 的键值源代码+详细教程.zip

    这个压缩包“Java 实例 - 遍历 HashTable 的键值源代码+详细教程.zip”包含了关于如何遍历`HashTable`的详细教程和源代码,对于学习Java的初学者或者需要深入了解`HashTable`操作的开发者来说,这是一个非常宝贵的...

    HashTable的java实现

    在Java编程语言中,哈希表(HashTable)是一种常见的数据结构,它提供了高效的数据存储和检索功能。哈希表基于哈希函数将键(Key)映射到数组的索引位置,通过键值对(Key-Value Pair)来存储数据。这种数据结构允许...

    Java 实例 - 使用 Enumeration 遍历 HashTable源代码+详细指导教程.zip

    通过本教程的源代码实例,你可以更直观地理解`HashTable`和`Enumeration`的使用方式,这对于学习Java基础和提升编程技能非常重要。记得实际动手操作,编写并运行代码,这样能更好地巩固你的理解。同时,查阅相关的...

    java-code Java语言程序.zip

    这个名为"java-code Java语言程序.zip"的压缩包很可能是包含了一系列的Java源代码文件,供学习、参考或直接使用。在Java编程中,我们通常会将相关代码组织成一个个的类(class),并保存为.java文件。一旦编写完成,...

    Java-J2SE学习笔记

    Java-J2SE学习笔记主要涵盖了Java编程语言的基础和核心概念,包括properties属性类、super关键字、this操作符、abstract抽象类、多态性、集合框架以及接口等关键知识点。以下是对这些主题的详细阐述: 1. **...

    java-all.pdf

    ### Java基础核心总结 #### 一、Java简介与环境配置 **Java** 是一种广泛使用的高级编程语言,由 Sun Microsystems 公司于1995年发布。...对于初学者而言,掌握这些基础知识是进一步学习 Java 的基石。

    java-se-summary-JavaSE相关的总结文章

    4. **集合框架**:Java集合框架是存储和管理对象的工具,包括List(ArrayList、LinkedList)、Set(HashSet、LinkedHashSet、TreeSet)和Map(HashMap、TreeMap、Hashtable)。泛型的引入增强了类型安全,避免了强制...

    java-programming-chapter-interview.zip_java programming

    2. HashMap与Hashtable:详解这两种映射结构,包括它们的工作原理和使用注意事项。 3. Map接口:理解键值对的概念,熟悉put、get、remove等操作。 4. 集合遍历:掌握迭代器和增强for循环的遍历方式。 五、多线程 1....

    计算机后端-Java-Java高并发从入门到面试教程-存思路.zip

    - **ConcurrentHashMap**:分析其线程安全的实现机制,对比`Hashtable`和`synchronized Map`。 - **BlockingQueue**:学习`ArrayBlockingQueue`、`LinkedBlockingQueue`等队列的用法,理解生产者-消费者模式。 3....

    JAVA-SE入门学习——第八讲集合

    以上内容涵盖了Java集合框架的基础知识,包括Collection接口、Set接口、List接口、Map接口的理解和使用,以及泛型、集合与数组的转换、集合的遍历和复制等重要概念。在实际开发中,掌握这些知识对于编写高效、安全的...

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

    Java集合专题总结:HashMap和HashTable源码学习和面试总结 本文总结了Java集合专题中的HashMap和HashTable,涵盖了它们的源码学习和面试总结。HashMap是一种基于哈希表的集合类,它的存储结构是一个数组,每个元素...

    HashMap与HashTable的区别(含源码分析)

    在Java编程语言中,`HashMap`和`HashTable`都是实现键值对存储的数据结构,但它们之间存在一些显著的区别,这些区别主要体现在...对于学习和理解,源码阅读是非常有价值的,可以帮助深入理解Java集合框架的设计原理。

    java-leetcode面试题解哈希表第187题重复的DNA序列-题解.zip

    在准备Java程序员的面试时,LeetCode是一个非常重要的平台,它提供了各种算法题目来测试和提升编程能力。...因此,深入学习和掌握哈希表是非常有价值的,它不仅在算法题中常见,也是许多实际开发场景下的首选数据结构。

    java问题集合适用于Java学习者

    Java 问题集合旨在帮助Java学习者巩固基础知识,其中包括类的作用域、集合框架的区别、字符编码、多线程实现以及垃圾回收机制等核心概念。 1. **类的作用域**: - `public`:任何地方都能访问。 - `private`:...

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

    - `java.util.Hashtable` 是线程安全的键值对映射容器,不允许 null 键或 null 值。 - **位集合类 BitSet** - `java.util.BitSet` 用于存储位字段,可以高效地进行位操作。 **1.1.3 Java IO包** - **数据流** ...

    Java 基础-尚硅谷学习笔记(含面试题) 2023年

    本资料“Java 基础-尚硅谷学习笔记(含面试题)2023年”旨在提供全面的Java基础知识,并结合最新的面试趋势,帮助学习者巩固基础并为面试做好准备。 1. **Java语法基础** - **变量与数据类型**:Java支持基本数据...

    java-leetcode面试题解哈希表第1207题独一无二的出现次数-题解.zip

    同时,也学习了Java 8的Stream API在处理集合数据时的强大功能。在求职面试中,这种问题经常被用来测试候选人的编程基础和解决问题的能力,因此熟练掌握此类题目的解法对于提升面试表现至关重要。

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

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

    java-leetcode面试题解哈希表第49题字母异位词分组-题解.zip

    总之,LeetCode第49题的解法展示了哈希表在处理字母异位词问题时的高效性和实用性,是学习和提高Java编程技巧的一个宝贵案例。通过反复练习和分析,开发者可以更好地掌握这类问题的解决策略,为求职面试做好充分准备...

Global site tag (gtag.js) - Google Analytics