谈一谈HashMap类2
1、由一个小案例引出本博文的讨论
- public class Demo1 {
- public static void main(String[] args) throws Exception {
- Student s1 = new Student();
- s1.setAge(10);
- int capacity = 2; // HashMap集合的容量
- HashMap<Student, String> stus = new HashMap<>(capacity, 1.0f);
- stus.put(s1, "s1");
- // 遍历HashMap
- Set<Entry<Student, String>> entrySet = stus.entrySet();
- for (Entry<Student, String> entry : entrySet) {
- System.out.println(entry.getKey().getAge() + "-" + entry.getValue());
- }
- System.out.println("== 分割线 ==");
- System.out.println("通过key获取value: " + stus.get(s1)); //s1
- s1.setAge(20);
- System.out.println("修改对象s1的age属性值后,通过key获取value: " + stus.get(s1)); // null
- }
- /**
- * HashMap类(jdk1.7.0_60)中的方法:计算Object的hash值
- */
- final static int hash(Object k) {
- int h = 0;
- if (0 != h && k instanceof String) {
- return sun.misc.Hashing.stringHash32((String) k);
- }
- h ^= k.hashCode();
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
- }
- public class Student {
- private String name;
- private int age;
- // getter和setter方法省略
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + age;
- result = prime * result + ((name == null) ? 0 : name.hashCode());
- return result;
- }
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- Student other = (Student) obj;
- if (age != other.age)
- return false;
- if (name == null) {
- if (other.name != null)
- return false;
- } else if (!name.equals(other.name))
- return false;
- return true;
- }
- }
控制台打印结果:
10-s1
== 分割线 ==
通过key获取value: s1
修改对象s1的age属性值后,通过key获取value: null
分析:
1)自定义了一个Student类,重写写hashCode()和equals()方法;然后创建了一个HashMap集合,往集合中添加一个元素stus.put(s1, "s1"),其中key为Student类型的对象s1;
2)然后,查找集合中指定key的value值,即执行代码stus.get(s1),可以获取到value值;
3)此时,修改对象s1的age属性值,再次执行代码stus.get(s1),就不能获取到value值,这是为什么呢?
2、查看HashMap类(jdk1.7.0_60)源码
- /**
- * 根据key获取value值
- */
- public V get(Object key) {
- if (key == null)
- return getForNullKey();
- Entry<K,V> entry = getEntry(key);
- return null == entry ? null : entry.getValue();
- }
- /**
- * 根据key获取Entry
- */
- final Entry<K,V> getEntry(Object key) {
- if (size == 0) {
- return null;
- }
- int hash = (key == null) ? 0 : hash(key);
- // indexFor(hash, table.length):根据key的hash值定位数组索引
- for (Entry<K,V> e = table[indexFor(hash, table.length)];
- e != null;
- e = e.next) {
- Object k;
- // 只有当e.hash == hash 并且 key相同时才能查找成功
- // 那么e.hash == hash?
- // 现在需要回答一个问题:修改Entry<key,value>的key的属性后,Entry的hash属性的值变吗?
- if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
- return e;
- }
- return null;
- }
3、修改Entry<key,value>的key的属性后,Entry的hash属性的值变吗?
- public class Demo1 {
- public static void main(String[] args) throws Exception {
- Student s1 = new Student();
- s1.setAge(10);
- System.out.println("hash(s1) = " + hash(s1));
- int capacity = 2; // HashMap集合的容量
- HashMap<Student, String> stus = new HashMap<>(capacity, 1.0f);
- stus.put(s1, "s1");
- // 遍历HashMap
- Set<Entry<Student, String>> entrySet = stus.entrySet();
- for (Entry<Student, String> entry : entrySet) {
- System.out
- .println(entry.getKey().getAge() + "-" + entry.getValue() + " entry对象的hash属性的值:" + getHash(entry));
- }
- System.out.println("== 分割线 ==");
- System.out.println("通过key获取value: " + stus.get(s1)); // s1
- s1.setAge(20);
- System.out.println("修改对象s1的age属性值后,hash(s1) = " + hash(s1));
- System.out.println("修改对象s1的age属性值后,通过key获取value: " + stus.get(s1)); // null
- for (Entry<Student, String> entry : entrySet) {
- System.out
- .println(entry.getKey().getAge() + "-" + entry.getValue() + " entry对象的hash属性的值:" + getHash(entry));
- }
- }
- /**
- * HashMap类(jdk1.7.0_60)中的方法:计算Object的hash值
- */
- final static int hash(Object k) {
- int h = 0;
- if (0 != h && k instanceof String) {
- return sun.misc.Hashing.stringHash32((String) k);
- }
- h ^= k.hashCode();
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
- /**
- * 自定义方法:通过反射获取Entry<?, ?>类型的对象的hash属性值
- */
- public static int getHash(Entry<?, ?> entry) throws Exception {
- Field field;
- field = entry.getClass().getDeclaredField("hash");
- field.setAccessible(true);
- int hash = (int) field.get(entry);
- return hash;
- }
- }
控制台打印结果:
hash(s1) = 1201
10-s1 entry对象的hash属性的值:1201
== 分割线 ==
通过key获取value: s1
修改对象s1的age属性值后,hash(s1) = 1603
修改对象s1的age属性值后,通过key获取value: null
20-s1 entry对象的hash属性的值:1201
分析:
根据控制台打印结果可知:修改Entry<key,value>中key的属性后,Entry的hash属性的值不变。
4、上面遇到的问题在put(key, value)也是一样的
- public class Demo2 {
- public static void main(String[] args) throws Exception {
- Student s1 = new Student();
- s1.setAge(10);
- int capacity = 2; // HashMap集合的容量
- HashMap<Student, String> stus = new HashMap<>(capacity, 1.0f);
- stus.put(s1, "s1");
- System.out.println("hash(s1)=" + hash(s1) + ", s1在哈希桶中存储的index:" + (hash(s1) % capacity));
- Set<Entry<Student, String>> entrySet = stus.entrySet();
- for (Entry<Student, String> entry : entrySet) {
- System.out.println(entry.getKey().getAge() + "-" + entry.getValue() + " entry对象的hash属性的值:" + getHash(entry));
- }
- System.out.println("== 分割线 ==");
- s1.setAge(20);
- stus.put(s1, "s1");
- System.out.println("hash(s1)=" + hash(s1) + ", 第二次添加s1在哈希桶中存储的index:" + (hash(s1) % capacity));
- for (Entry<Student, String> entry : entrySet) {
- System.out.println(entry.getKey().getAge() + "-" + entry.getValue() + " entry对象的hash属性的值:" + getHash(entry));
- }
- }
- /**
- * HashMap类中的方法:计算Object的hash值
- */
- final static int hash(Object k) {
- int h = 0;
- if (0 != h && k instanceof String) {
- return sun.misc.Hashing.stringHash32((String) k);
- }
- h ^= k.hashCode();
- h ^= (h >>> 20) ^ (h >>> 12);
- return h ^ (h >>> 7) ^ (h >>> 4);
- }
- /**
- * 自定义方法:通过反射获取Entry<?, ?>类型的对象的hash属性值
- */
- public static int getHash(Entry<?, ?> entry) throws Exception {
- Field field;
- field = entry.getClass().getDeclaredField("hash");
- field.setAccessible(true);
- int hash = (int) field.get(entry);
- return hash;
- }
- }
控制台打印结果:
hash(s1)=1201, s1在哈希桶中存储的index:1
10-s1 entry对象的hash属性的值:1201
== 分割线 ==
hash(s1)=1603, 第二次添加s1在哈希桶中存储的index:1
20-s1 entry对象的hash属性的值:1603
20-s1 entry对象的hash属性的值:1201
查看HashMap类(jdk1.7.0_60) put(key,value) 方法的源码
- public V put(K key, V value) {
- if (table == EMPTY_TABLE) {
- inflateTable(threshold);
- }
- if (key == null)
- return putForNullKey(value);
- int hash = hash(key);
- int i = indexFor(hash, table.length);
- 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;
- }
- }
- modCount++;
- addEntry(hash, key, value, i);
- return null;
- }
============================================================================
需要修改 s1 对象的属性,先从 HashMap 中删除,在重写放入
- public static void main(String[] args) throws Exception {
- Student s1 = new Student();
- s1.setAge(10);
- int capacity = 2; // HashMap集合的容量
- HashMap<Student, String> stus = new HashMap<>(capacity, 1.0f);
- stus.put(s1, "s1");
- // 遍历HashMap
- Set<Map.Entry<Student, String>> entrySet = stus.entrySet();
- for (Map.Entry<Student, String> entry : entrySet) {
- System.out.println(entry.getKey().getAge() + "-" + entry.getValue());
- }
- System.out.println("== 分割线 ==");
- System.out.println("通过key获取value: " + stus.get(s1)); //s1
- // 需要修改 s1 对象的属性,先从 HashMap 中删除,在重写放入
- stus.remove(s1);
- s1.setAge(20);
- stus.put(s1, "s1");
- System.out.println("修改对象s1的age属性值后,通过key获取value: " + stus.get(s1)); // s1
- // 遍历HashMap
- entrySet = stus.entrySet();
- for (Map.Entry<Student, String> entry : entrySet) {
- System.out.println(entry.getKey().getAge() + "-" + entry.getValue());
- }
- }
---
谈一谈HashMap类2的更多相关文章
- 谈一谈HashMap类
一.Java中的hashCode()和equals() 1. hashCode()的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode()是用来在散列存储结构中确定对 ...
- 谈一谈Java8的函数式编程(二) --Java8中的流
流与集合 众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...
- 谈一谈泛型(Generic)
谈一谈泛型 首先,泛型是C#2出现的.这也是C#2一个重要的新特性.泛型的好处之一就是在编译时执行更多的检查. 泛型类型和类型参数 泛型的两种形式:泛型类型( 包括类.接口.委托和结构 没有泛型枚 ...
- 谈一谈深度学习之semantic Segmentation
上一次发博客已经是9月份的事了....这段时间公司的事实在是多,有写博客的时间都拿去看paper了..正好春节回来写点东西,也正好对这段时间做一个总结. 首先当然还是好好说点这段时间的主要工作:语义分 ...
- 谈一谈并查集QAQ(上)
最近几日理了理学过的很多oi知识...发现不知不觉就有很多的知识忘记了... 在聊聊并查集的时候顺便当作巩固吧.... 什么是并查集呢? ( Union Find Set ) 是一种用于处理分离集合的 ...
- 谈一谈C#的事件
谈一谈C#的事件 C#中事件基于委托,要理解事件要先理解委托,如果觉得自己关于委托不是很了解可以看看我前面写委托的文章 事件基于委托,是一种功能受限的委托,为委托提供了一种发布/订阅机制 使用委托时, ...
- Hashtable和HashMap类的区别
Hashtable和HashMap类有三个重要的不同之处.第一个不同主要是历史原因.Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现. ...
- Java API —— HashMap类 & LinkedHashMap类
1.HashMap类 1)HashMap类概述 键是哈希表结构,可以保证键的唯一性 2)HashMap案例 HashMap<String,String> ...
- JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口<HashMap类、TreeMap类>)
Java的集合可以分为两种,第一种是以数组为代表的线性表,基类是Collection:第二种是以Hashtable为代表的键值对. ... 线性表,基类是Collection: 数组类: person ...
随机推荐
- 【重新分配分片】Elasticsearch通过reroute api重新分配分片
elasticsearch可以通过reroute api来手动进行索引分片的分配. 不过要想完全手动,必须先把cluster.routing.allocation.disable_allocation ...
- ssm项目中遇到微信用户名称带有表情,插入失败问题
ssm项目中遇到微信用户名称带有表情,插入失败问题 问题 Mysql的utf8编码最多3个字节,而Emoji表情或者某些特殊字符是4个字节. 因此会导致带有表情的昵称插入数据库时出错. 解决方法 一. ...
- 关不掉.vbs
创建: 1.在桌面新建一个 关不掉.txt 文本文档 2.打开输入一下内容 do msgbox"信不信你关不掉我" msgbox"哈哈,你相信了吧" msgbo ...
- k8s2
1.主节点与子节点如何沟通,交互 apiServer <==> kublet 2. pod之间如何共享, 使用volumn(数据卷 ) kube-proxy 和 service 配置好网络 ...
- kubernetes 实战4_命令_Configure Pods and Containers
Configure Service Accounts for Pods A service account provides an identity for processes that run in ...
- Lintcode415-Valid Palindrome-Medium
Given a string, determine if it is a palindrome, considering only alphanumeric(字母和数字) characters and ...
- 【Selenium2】【selenium之 定位以及切换frame(iframe)】
参考:http://blog.csdn.net/huilan_same/article/details/52200586 总有人看不明白,以防万一,先在开头大写加粗说明一下: frameset不用切, ...
- P1182 数列分段`Section II`
传送门 思路: 求数列每段和的最大值的最小值,很明显是用二分法求解,加贪心检验.本题关键是要怎么去高效的check,可以考虑一个贪心的思路,能加的就加上,不能则新开一段,so对于二分的值 u ,我们从 ...
- zipkin启动报错(Caused by: java.lang.ClassNotFoundException: zipkin.Component)的解决方法
使用ziplin依赖: <dependency> <groupId>org.springframework.cloud</groupId> <artifact ...
- 在未排序的数组中找到第 k 个最大的元素
在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 ...