谈一谈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 ...
随机推荐
- PowerShell Gallery
https://docs.microsoft.com/en-us/powershell/gallery/getting-started https://www.powershellgallery.co ...
- sublime使用技巧总结
软件右下角可以选择文档语法模式 Ctrl + Shift + P ------------------命令模式sshtml模糊匹配-----语法切换到html模式,同理所得,ss+相应文件名匹配相应模 ...
- R语言之正则表达式
常见与正则表达式相关的函数: grep(pattern, x, ignore.case = FALSE, perl = FALSE, value = FALSE, fixed = FALSE, use ...
- 4-Five-Youth
①People are always talking about 'the problem of youth'. If there is one--which I take leave to do ...
- c# 后台post,包含file文件
http request 相关 private bool Upload(KeyValuePair<string, string>[] paramString,Stream paramFil ...
- facebook api之Ad
Ad Contains information to display an ad and associate it an ad set. Each ad is associated with an a ...
- 浅谈 Make 命令
代码变成可执行文件,叫做编译(compile):先编译这个,还是先编译那个(即编译的安排),叫做构建(build). Make是最常用的构建工具,诞生于1977年,主要用于C语言的项目.但是实际上 , ...
- openlayers空间点查询之GetFeatureInfo
在map对象上注册点击方法监听, 这里我用的是wms,当然你也可以查询wfs map.events.register('click', map, function (e) { ...
- C+++string类如何判断字符串为空
string类是C++STL类之一,有很丰富的接口,判断string为空是经常用到的操作. string类为空,实际也就是元素为0个. 可以按照如下方式判断: 1.string类有自己的成员函数emp ...
- mariaDB中文乱码
cetos7 下 http://hongjun.blog.51cto.com/445761/400985 1 . copy 一个文件成 /etc/my.cnf cp /usr/share/mysql ...