对于HashSet而言,系统采用Hash算法决定集合元素的存储位置,这样可以保证快速存取集合元素;

对于HashMap,系统将value当成key的附属,系统根据Hash算法来决定key的存储位置,这样可以保证快速存取集合key,而value总是紧随key存储。

(这些集合虽然号称存储的是java对象,但实际上并不会真正将java对象放入set集合中,而只是在Set集合中保留这些对象的引用。

当程序视图将多个key-value 放入HashMap中时,采用一种“Hash算法”来决定每个元素的存储位置。

 1 public V put(K key, V value)
2 {
3 if(key == null)
4 return putForNullKey(value);
5 int hash = hash(key.hashCode());
6
7 int i = indexFor(hash, table.length);
8
9 for(Entry<K,V> e = table[i]; e!=null;e=e.next)
10 {
11 Object K;
12 if(e.hash==hash && ((k=e.key) == k || key.equals(k))
13 {
14 V oldValue = e.value;
15 e.value= value;
16 e.recordAccess(this);
17 return oldValue;
18 }
19 }
20 modCount ++;
21 addEnrty(hash,key,value,i);
22 return null;
23 }

一个重要的内部接口Map.Entry,每个Map.Entry其实就是一个Key-Value对。当系统决定存储HashMap中的key-value对是,只是根据key来计算并决定每个Entry的存储位置:如果两个Entry的key的hashCode()返回值相同,那么它们的存储位置相同;如果这两个key通过equals比较返回true,新添加的Entry的value将覆盖原有Entry的value,但key不会覆盖;如果这两个key通过equals比较返回false,新添加的Entry将与集合中原有Entry形成Entry链。见addEntry()方法:

1 void addEntry(int hash,K key,V value,int bucketIndex)
2 {
3 Entry<K,V> e = table[bucketIndex];
4 table[bucketIndex] = new Entry<K,V>(hash,key,value,e);
5 if(size++ >= threshold) //threshold包含HashMap能容纳的key-value对的极限。
6 resize(2*table.length);
7 }

table实质就是一个普通数组,每个数组都有一个固定一的长度,这个数组的长度就是HashMap的容量。

HashSet是基于HashMap实现的,HashSet底层采用HashMap来保存所有元素。

 1 class Name
2 {
3 private String first;
4 private String last;
5 public Name(String first, String last)
6 {
7 this.first = first;
8 this.last = last;
9 }
10 public boolean equals(Object o)
11 {
12 if(this == o)
13 return true;
14 if(o.getClass() == Name.class)
15 {
16 Name n =(Name) o;
17 return n.first.equals(first) && n.last.equals(last);
18 }
19 return false;
20 }
21
22 public class HashSetTest
23 {
24 public static void main(String[] args)
25 {
26 Set<Name> s = new HashSet<Name>();
27 s.add(new Name("abc","123"));
28 System.out.println(s.contains(new Name("abc","123");
29 }
30 }
31

运行结果是false.

因为HashSet判断两个对象相等的标准除了要求通过equals方法比较返回true外,还要求两个对象的hashCode()返回值相等。

重写hashCode()方法:

public int hashCode()

{

    return first.hashCode();

}

public boolean equals(Object o)

{

  ....

  if(o.getClass() == Name.class)

  {

    Name n = (Name) o;

    return n.first.equals(first);

  }

  ...

}

HashMap 和 HashSet的更多相关文章

  1. HashMap底层实现原理/HashMap与HashTable区别/HashMap与HashSet区别

    ①HashMap的工作原理 HashMap基于hashing原理,我们通过put()和get()方法储存和获取对象.当我们将键值对传递给put()方法时,它调用键对象的hashCode()方法来计算h ...

  2. 谁可以说出HashMap和HashSet的相同点和不同点。

    谁可以说出HashMap和HashSet的相同点和不同点. 2011-11-15 20:46ruoshui_t | 浏览 20310 次  Perl 2011-11-15 21:17 #知道行家专业创 ...

  3. [转] HashMap和HashSet的区别

    HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题不涉及到HashSet和H ...

  4. HashMap和HashSet的区别

    理解HashSet及使用 HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的面试,可以说是不完整.而Collection框架的问题 ...

  5. [置顶] HashMap HashTable HashSet区别剖析

    HashMap.HashSet.HashTable之间的区别是Java程序员的一个常见面试题目,在此仅以此博客记录,并深入源代码进行分析: 在分析之前,先将其区别列于下面 1:HashSet底层采用的 ...

  6. HashMap、HashSet源代码分析其 Hash 存储机制

    集合和引用 就像引用类型的数组一样,当我们把 Java 对象放入数组之时,并不是真正的把 Java 对象放入数组中,只是把对象的引用放入数组中,每个数组元素都是一个引用变量. 实际上,HashSet ...

  7. HashMap HashTable HashSet

    原文转载自 http://blog.csdn.net/wl_ldy/article/details/5941770 HashMap是新框架中用来代替HashTable的类 也就是说建议使用HashMa ...

  8. 【转】HashMap和HashSet的区别

    原文网址:http://www.importnew.com/6931.html HashMap和HashSet的区别是Java面试中最常被问到的问题.如果没有涉及到Collection框架以及多线程的 ...

  9. HashMap HashTable HashSet区别剖析

    HashMap.HashSet.HashTable之间的区别是Java程序员的一个常见面试题目,在此仅以此博客记录,并深入源代码进行分析: 在分析之前,先将其区别列于下面 1:HashSet底层采用的 ...

  10. java该HashTable,HashMap和HashSet

    同一时候我们也对HashSet和HashMap的核心方法hashcode进行了具体解释,见<探索equals()和hashCode()方法>. 万事俱备,那么以下我们就对基于hash算法的 ...

随机推荐

  1. 重装系统——联想window 10

    大四了,读了四年大学,唉,混的,啥也不会,工作也找不到,真的不知道这大学四年到底干了什么.专业是计算机方向的,但居然,不敢,也不会装电脑系统,大学四年的文件都是乱放的,更那个的是,有些软件卸载不完全, ...

  2. webpack 之js兼容性处理

    webpack 之js兼容性处理 // 用来拼接绝对路径的方法 const {resolve} = require('path') const HtmlWebpackPlugin = require( ...

  3. Java 初始化与清理

    用构造器确保初始化 如何自定义构造器(constructor)? 构造器方法的名称与类名相同,并且没有返回值. 需要注意,在定义构方法时,方法名前面不要添加任何的类型说明符,格式:类名(){},构造方 ...

  4. 菜鸡的Java笔记 类图

    类图        1.如何实现类图的描述        2.时序图的使用                    从实际i的开发标准:应该在项目编写钱设计类图        而现在的开发大部分情况下, ...

  5. N体模拟数据可视化 LightningChart®

    N体模拟数据可视化 LightningChart ​ N体模拟也许是目前最先进的数据可视化类型之一.事实上,我们现在谈论的不再是以商业为中心的传统数据的可视化,现在它甚至超越了比如振动分析等先进数据源 ...

  6. [bzoj1146]网络管理

    发现是链上的问题,所以树链剖分发现要查询第k大,因为第k大不支持合并,所以要二分答案二分答案后相当于询问一些区间内大于某数的数个数,直接线段树套平衡树即可时间复杂度$o(nlog^{4}_n)$(跟$ ...

  7. Chrome 插件特性及实战场景案例分析

    一.前言 提起Chrome扩展插件(Chrome Extension),每个人的浏览器中或多或少都安装了几个插件,像一键翻译.广告屏蔽.录屏等等,通过使用这些插件,可以有效的提高我们的工作效率:但有时 ...

  8. 第05章 MySQL排序与分页

    第05章 MySQL排序与分页 1. 排序数据 1.1 排序规则 使用 ORDER BY 子句排序 ASC(ascend): 升序 DESC(descend):降序 ORDER BY 子句在SELEC ...

  9. airTest小程序自动化踩坑记(android设备)

    一:怎么开启微信小程序的webview调试定位元素 操作如下(android设备): 1.打开X5内核的方法在聊天窗口任意输入"http://debugx5.qq.com" 点击& ...

  10. 从零开始,使用Dapr简化微服务

    序言 现有的微服务模式需要再业务代码中集成大量基础设施模块,比如注册中心,服务发现,服务调用链路追踪,请求熔断,重试限流等等,使得系统过于臃肿重量级. Dapr作为新一代微服务模式,使用sidecar ...