`
cuisuqiang
  • 浏览: 3962869 次
  • 性别: Icon_minigender_1
  • 来自: 北京
博客专栏
3feb66c0-2fb6-35ff-968a-5f5ec10ada43
Java研发技术指南
浏览量:3672225
社区版块
存档分类
最新评论

java中HashMap学习

    博客分类:
  • JDK
阅读更多

什么是HashMap
HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象。当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算hashcode,让后找到bucket位置来储存值对象。当获取对象时,通过键对象的equals()方法找到正确的键值对,然后返回值对象。HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。

public V put(K key, V value) {
 if (key == null)
  return putForNullKey(value);
 int hash = hash(key.hashCode());
 int i = indexFor(hash, table.length);  // bucket位置
 for (Entry<K,V> e = table[i]; e != null; e = e.next) {
  Object k;
  if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
   V oldValue = e.value;
   e.value = value;
   e.recordAccess(this);
   return oldValue; // 如果该Key已经存在,会返回之前保存的值
  }
 }

 modCount++;
 addEntry(hash, key, value, i);
 return null;
}
public V get(Object key) {
 if (key == null)
  return getForNullKey();
 int hash = hash(key.hashCode());
 for (Entry<K,V> e = table[indexFor(hash, table.length)];
   e != null;
   e = e.next) {
  Object k;
  if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
   return e.value;
 }
 return null;
}

 

 

当两个对象的hashcode相同会发生什么?
它们会储存在同一个bucket位置的链表中。键对象的equals()方法用来找到键值对。

如果HashMap的大小超过了负载因子定义容量,怎么办?
默认的负载因子大小为0.75,也就是说,当一个map填满了75%的bucket时候,和其它集合类(如ArrayList等)一样,将会创建原来HashMap大小的两倍的bucket数组,来重新调整map的大小,并将原来的对象放入新的bucket数组中。这个过程叫作rehashing,因为它调用hash方法找到新的bucket位置。

addEntry(hash, key, value, i);

void addEntry(int hash, K key, V value, int bucketIndex) {
 Entry<K,V> e = table[bucketIndex];
 table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
 if (size++ >= threshold)
  resize(2 * table.length);
}

void resize(int newCapacity) {
 Entry[] oldTable = table;
 int oldCapacity = oldTable.length;
 if (oldCapacity == MAXIMUM_CAPACITY) {
  threshold = Integer.MAX_VALUE;
  return;
 }
 Entry[] newTable = new Entry[newCapacity];
 transfer(newTable);
 table = newTable;
 threshold = (int)(newCapacity * loadFactor);
}

 
如果使用的是默认,即直接new HashMap<String, Object>(),那么在put第12个元素时,就会进行resize操作

static final int DEFAULT_INITIAL_CAPACITY = 16;
static final float DEFAULT_LOAD_FACTOR = 0.75f;
public HashMap() {
 this.loadFactor = DEFAULT_LOAD_FACTOR;
 threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
 table = new Entry[DEFAULT_INITIAL_CAPACITY];
 init();
}

 
所以你应该评估自己可能缓存的数量,使用HashMap(int initialCapacity, float loadFactor)构造一个带指定初始容量和加载因子的空 HashMap。

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);

 // Find a power of 2 >= initialCapacity
 int capacity = 1;
 while (capacity < initialCapacity)
  capacity <<= 1;

 this.loadFactor = loadFactor;
 threshold = (int)(capacity * loadFactor);
 table = new Entry[capacity];
 init();
}

 

重新调整HashMap大小存在什么问题
当重新调整HashMap大小的时候,存在条件竞争,因为如果两个线程都发现HashMap需要重新调整大小了,它们会同时试着调整大小。在调整大小的过程中,存储在链表中的元素的次序会反过来,因为移动到新的bucket位置的时候,HashMap并不会将元素放在链表的尾部,而是放在头部,这是为了避免尾部遍历(tail traversing)。如果条件竞争发生了,那么就死循环了。
上面看到resize会操作table,而操作方法本身和table都是非线程安全

 

为什么String, Interger这样的wrapper类适合作为键
String,Interger这样的wrapper类作为HashMap的键是再适合不过了,而且String最为常用。因为String是不可变的,也是final的,而且已经重写了equals()和hashCode()方法了。其他的wrapper类也有这个特点。不可变性是必要的,因为为了要计算hashCode(),就要防止键值改变,如果键值在放入时和获取时返回不同的hashcode的话,那么就不能从HashMap中找到你想要的对象。不可变性还有其他的优点如线程安全。如果你可以仅仅通过将某个field声明成final就能保证hashCode是不变的,那么请这么做吧。因为获取对象的时候要用到equals()和hashCode()方法,那么键对象正确的重写这两个方法是非常重要的。如果两个不相等的对象返回不同的hashcode的话,那么碰撞的几率就会小些,这样就能提高HashMap的性能。

 

我们可以使用自定义的对象作为键吗
当然你可能使用任何对象作为键,只要它遵守了equals()和hashCode()方法的定义规则,并且当对象插入到Map中之后将不会再改变了。如果这个自定义对象时不可变的,那么它已经满足了作为键的条件,因为当它创建之后就已经不能改变了。

 

请您到ITEYE网站看 java小强 原创,谢谢!

http://cuisuqiang.iteye.com/ 

自建博客地址:http://www.javacui.com/ ,内容与ITEYE同步!

分享到:
评论

相关推荐

    Java-HashMap.rar_hashmap_java hashmap

    在Java编程语言中,`HashMap`是`java.util`包中的一个核心类,它属于集合框架的一部分,主要用于存储键值对的数据结构。`HashMap`基于哈希表(散列表)实现,提供了快速的插入、删除和查找操作,平均时间复杂度为O(1...

    深入Java集合学习系列:HashMap的实现原理

    在Java编程语言中,集合框架是开发者日常工作中不可或缺的一部分,HashMap作为其中的重要成员,它的实现原理对于理解Java性能优化和数据结构有深远的意义。HashMap是一个基于哈希表的数据结构,它实现了Map接口,...

    马士兵老师HashMap学习笔记

    总的来说,马士兵老师的HashMap学习笔记不仅涵盖了HashMap的基础知识,还深入探讨了其在不同JDK版本中的实现细节,特别是并发环境下的问题和解决方案。理解这些内容对于提升Java编程技能和优化代码性能具有重要价值...

    java代码-使用java解决手写hashMap的源代码

    java代码-使用java解决手写hashMap的源代码 ——学习参考资料:仅用于个人学习使用!

    java在hashmap初始化时赋初值过程解析

    Java 中的 HashMap 是一种常用的数据结构,一般用来做数据字典或者 Hash 查找的容器。在初始化并赋初值时,我们通常使用 `HashMap, Object&gt; map = new HashMap();` 的方式初始化,然后使用 `put` 方法添加键值对。...

    2022年Java中对HashMap的深度分析Java教程.docx

    在Java编程语言中,HashMap是Java集合框架的重要组成部分,它提供了高效的存储和检索对象的能力,实现了"键-值"对的映射。本教程将深入分析2022...因此,深入学习HashMap的内部实现对于Java开发者来说是非常有价值的。

    java7hashmap源码-network_program:学习java网络编程

    java网络编程学习 简介 用于存放学习java网络编程过程遇见的重难点笔记和相关代码 附带代码大部分是《java网络编程 第四版》的课程代码 对运算字符串进行识别的作业 @since2020.11.26 IO流 - 多线程 @since2020.11....

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

    本文总结了Java集合专题中的HashMap和HashTable,涵盖了它们的源码学习和面试总结。HashMap是一种基于哈希表的集合类,它的存储结构是一个数组,每个元素是一个单链表的头节点,链表用来解决hash地址冲突问题。...

    JNI处理各种类型数据,不包含获取Java的HashMap

    这个压缩包中的示例工程包含了Java和C++的代码,可以作为学习和实践JNI处理不同类型数据的参考。你可以直接运行这些代码,观察其工作原理。同时,提供的参考资料也会帮助你深入理解JNI的工作机制和最佳实践。 总之...

    深入解读大厂java面试必考点之HashMap全套学习资料

    HashMap是Java编程语言中最常用的集合类之一,尤其在面试中,HashMap的相关知识是考察候选人对数据结构和算法理解的重要部分。本套学习资料全面涵盖了HashMap的深入解析,旨在帮助求职者掌握大厂面试中的核心知识点...

    Java8 HashMap的实现原理分析

    Java8之后新增挺多新东西,接下来通过本文给大家介绍Java8 HashMap的实现原理分析,对java8 hashmap实现原理相关知识感兴趣的朋友一起学习吧

    java实现运用hashmap充当购物车goodbean充当存放数据.pdf

    在本资源中,我们将学习如何使用 Java 语言实现一个简单的购物车系统,其中使用 HashMap 来存放用户想买的商品信息。下面是该资源中的知识点总结: ConnDB.java ConnDB.java 是一个用于连接数据库的类,该类中...

    java7hashmap源码-backend-study:后端学习之路

    随着Java学习的不断深入,发现很多知识在脑海里都是一个个碎片,建此仓库的目的希望把零碎的知识点都整合起来,提高自己的学习效率。欢迎志同道合的朋友,一起来维护该仓库 目录 网络基础 WEB TCP协议 HTTP/HTTPS ...

    学习Java HashMap,看这篇就够了

    "Java HashMap 详解" Java HashMap 是一种常用的数据结构,它实现了 Map 接口,根据键的 HashCode 值存储数据,具有很快的访问速度。HashMap 是一个散列表,它存储的内容是键值对(key-value)映射。 HashMap 的...

    Java基础 学习笔记 Markdownr版

    2. 集合:在13集合.md中,详细讲解了Java集合框架,包括ArrayList、LinkedList、HashSet、HashMap等基本集合类的使用,以及List、Set、Map接口的特性。此外,还可能涉及泛型的概念,泛型(14泛型.md)提高了代码的...

    java7hashmap源码-Excellent-Blog-share:欢迎分享优秀博客

    hashmap源码 Excellent-Blog-share Welcome to share excellent blogs . 当你的能力还驾驭不了你的目标时,就应该沉下心来历练 当你的才华还撑不起你的野心时,那你就应该静下心来学习 #目录 ###附录 java系列 java8...

    本仓库记录了我的Java学习进阶之路,涵盖了Java基础、JDK源码、JVM中的重要知识,附有代码和博客讲解,旨在提供一个Java在线共享学习平台,帮助更多的Java学习入门者进阶 .zip

    作者目录Java基础Java基础学习(1)——引用Java基础学习(2)——注解Java基础学习(3)——泛型Java基础学习(4)——动态代理《Java多线程核心技术》读书笔记JDK源Java集合框架源码解读(1)——ArrayList、LinkedList和...

    java集合深度学习

    在深入学习Java集合时,我们需要特别关注HashMap和HashTable这两个重要的类。虽然它们都是用于存储键值对的数据结构,但它们在设计和使用上有显著的区别。 HashMap是Java 1.2引入的,它是Map接口的一个实现,提供了...

    java7hashmap源码-learn-java-source:学习java源码,java1.8

    总的来说,学习HashMap的源码能够帮助我们深入理解Java的数据结构和算法,以及如何在实际应用中高效地使用它们。通过分析源码,我们可以了解Java 7 HashMap的设计思想,为解决并发问题提供思路,并为升级到更高级的...

Global site tag (gtag.js) - Google Analytics