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的更多相关文章

  1. 谈一谈HashMap类

    一.Java中的hashCode()和equals() 1. hashCode()的存在主要是用于查找的快捷性,如Hashtable,HashMap等,hashCode()是用来在散列存储结构中确定对 ...

  2. 谈一谈Java8的函数式编程(二) --Java8中的流

    流与集合    众所周知,日常开发与操作中涉及到集合的操作相当频繁,而java中对于集合的操作又是相当麻烦.这里你可能就有疑问了,我感觉平常开发的时候操作集合时不麻烦呀?那下面我们从一个例子说起. 计 ...

  3. 谈一谈泛型(Generic)

    谈一谈泛型 首先,泛型是C#2出现的.这也是C#2一个重要的新特性.泛型的好处之一就是在编译时执行更多的检查. 泛型类型和类型参数 ​ 泛型的两种形式:泛型类型( 包括类.接口.委托和结构 没有泛型枚 ...

  4. 谈一谈深度学习之semantic Segmentation

    上一次发博客已经是9月份的事了....这段时间公司的事实在是多,有写博客的时间都拿去看paper了..正好春节回来写点东西,也正好对这段时间做一个总结. 首先当然还是好好说点这段时间的主要工作:语义分 ...

  5. 谈一谈并查集QAQ(上)

    最近几日理了理学过的很多oi知识...发现不知不觉就有很多的知识忘记了... 在聊聊并查集的时候顺便当作巩固吧.... 什么是并查集呢? ( Union Find Set ) 是一种用于处理分离集合的 ...

  6. 谈一谈C#的事件

    谈一谈C#的事件 C#中事件基于委托,要理解事件要先理解委托,如果觉得自己关于委托不是很了解可以看看我前面写委托的文章 事件基于委托,是一种功能受限的委托,为委托提供了一种发布/订阅机制 使用委托时, ...

  7. Hashtable和HashMap类的区别

    Hashtable和HashMap类有三个重要的不同之处.第一个不同主要是历史原因.Hashtable是基于陈旧的Dictionary类的,HashMap是Java 1.2引进的Map接口的一个实现. ...

  8. Java API —— HashMap类 & LinkedHashMap类

    1.HashMap类 1)HashMap类概述         键是哈希表结构,可以保证键的唯一性 2)HashMap案例         HashMap<String,String>   ...

  9. JAVA中的数据结构——集合类(线性表:Vector、Stack、LinkedList、set接口;键值对:Hashtable、Map接口<HashMap类、TreeMap类>)

    Java的集合可以分为两种,第一种是以数组为代表的线性表,基类是Collection:第二种是以Hashtable为代表的键值对. ... 线性表,基类是Collection: 数组类: person ...

随机推荐

  1. 题解——CF Manthan, Codefest 18 (rated, Div. 1 + Div. 2) T3(贪心)

    是一道水题 虽然看起来像是DP,但其实是贪心 扫一遍就A了 QwQ #include <cstdio> #include <algorithm> #include <cs ...

  2. Twenty score

    1.上图中有两个人对读书的看法有较大的不同. There are two people in the cartoon who treat books in completely different w ...

  3. js判断数字、整数、字符串、布尔,特殊方法

    整数: function isInteger(obj) { return Math.floor(obj) === obj } isInteger(3) // true isInteger(3.3) / ...

  4. 前端面试总结 (转 0C°)

    前端面试总结 1.一些开放性题目 1.自我介绍:除了基本个人信息以外,面试官更想听的是你与众不同的地方和你的优势. 2.项目介绍 3.如何看待前端开发? 4.平时是如何学习前端开发的? 5.未来三到五 ...

  5. 【Mysql】【Navicat For Mac】Navicat Premium for Mac v12.0.23 + macOS Sierra 10.12.6

    参考地址:https://blog.csdn.net/womeng2009/article/details/79700667 [备注]我只用到了部分信息,就激活了 内容: Navicat Premiu ...

  6. Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) E. Cards Sorting 树状数组

    E. Cards Sorting time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  7. Java中的单实例

    前几天刚学完单实例设计模式,今天看代码时发现一行代码很奇怪,getRuntime()函数的返回类型怎么是它本身,忽然想起前几天学的单实例模式,于是找到方法的定义,果然是静态私有变量,获取实例的公有方法 ...

  8. nginx 启动报错 1113: No mapping for the Unicode character exists in the target multi-byte code

    failed (1113: No mapping for the Unicode character exists in the target multi-byte code page) 因为路径有中 ...

  9. QT文件(夹)操作---QFile、QDir、QFileInfo、QTextStream和QDataStream异同

    1.1    文件和目录 QFile.QBuffer和QTcpSocket可支持读写设备,用open函数打开,用write或putChar函数写入.用read和readLine或readAll进行读取 ...

  10. Django - models.py 应用

    Django - models.py 应用 编写 models.py 文件 from django.db import models # Create your models here. class ...