HasnMap中的键
来源:互联网 发布:linux gzip 解压 编辑:程序博客网 时间:2024/04/28 21:59
1. 默认的Object, equals()方法对引用对象来说比较的是地址;
2.默认的Object, hashCode()方法用对象的地址来计算hash值,返回是int型;
3.一定要同时重写equals和hashCode()方法,理由可以参考HashMap的get源码;
public V get(Object key) { if (key == null) return getForNullKey(); Entry<K,V> entry = getEntry(key); return null == entry ? null : entry.getValue(); }
final Entry<K,V> getEntry(Object key) { if (size == 0) { return null; } int hash = (key == null) ? 0 : hash(key); 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 != null && key.equals(k)))) return e; } return null; }
1、什么是可变对象
可变对象是指创建后自身状态能改变的对象。换句话说,可变对象是该对象在创建后它的哈希值可能被改变。
在下面的代码中,对象MutableKey的键在创建时变量 i=10 j=20,哈希值是1291。
然后我们改变实例的变量值,该对象的键 i 和 j 从10和20分别改变成30和40。现在Key的哈希值已经变成1931。
显然,这个对象的键在创建后发生了改变。所以类MutableKey是可变的。
让我们看看下面的示例代码:
注意:调用hashCode()时,equals()方法也同时被执行。
publicclassMutableDemo { publicstaticvoid main(String[] args) { // Object created MutableKey key = new MutableKey(10,20); System.out.println("Hash code: " + key.hashCode()); // Object State is changed after object creation. key.setI(30); key.setJ(40); System.out.println("Hash code: " + key.hashCode()); }}
输出:Hash code: 1291Hash code: 1931
2、HashMap如何存储键值对
HashMap用Key的哈希值来存储和查找键值对。
当插入一个Entry时,HashMap会计算Entry Key的哈希值。Map会根据这个哈希值把Entry插入到相应的位置。
查找时,HashMap通过计算Key的哈希值到特定位置查找这个Entry。
3、在HashMap中使用可变对象作为Key带来的问题
如果HashMap Key的哈希值在存储键值对后发生改变,Map可能再也查找不到这个Entry了。
如果Key对象是可变的,那么Key的哈希值就可能改变。在HashMap中可变对象作为Key会造成数据丢失。
下面的例子将会向你展示HashMap中有可变对象作为Key带来的问题。
public class MutableKey { private int i; private int j; public MutableKey(inti, intj) { this.i = i; this.j = j; } public final int getI() { returni; } public final void setI(inti) { this.i = i; } public final int getJ() { returnj; } public final void setJ(intj) { this.j = j; } @Override publicint hashCode() { final int prime = 31; int result = 1; result = prime * result + i; result = prime * result + j; return result; } @Override publicboolean equals(Object obj) { if(this== obj) { returntrue; } if(obj == null) { return false; } if(!(obj instanceof MutableKey)) { return false; } MutableKey other = (MutableKey) obj; if(i != other.i) { return false; } if(j != other.j) { return false; } return true; }}
importjava.util.HashMap;importjava.util.Map; publicclass MutableDemo1 { publicstatic void main(String[] args) { // HashMap Map<MutableKey, String> map = new HashMap<>(); // Object created MutableKey key = new MutableKey(10,20); // Insert entry. map.put(key,"Robin"); // This line will print 'Robin' System.out.println(map.get(key)); // Object State is changed after object creation. // i.e. Object hash code will be changed. key.setI(30); // This line will print null as Map would be unable to retrieve the // entry. System.out.println(map.get(key)); }}输出:
Robin
null
4、如何解决
在HashMap中使用不可变对象。在HashMap中,使用String、Integer等不可变类型用作Key是非常明智的。
我们也能定义属于自己的不可变类。
如果可变对象在HashMap中被用作键,那就要小心在改变对象状态的时候,不要改变它的哈希值了。
在下面的Employee示例类中,哈希值是用实例变量id来计算的。一旦Employee的对象被创建,id的值就能再改变。只有name可以改变,但name不能用来计算哈希值。所以,一旦Employee对象被创建,它的哈希值不会改变。所以Employee在HashMap中用作Key是安全的。
示例代码:
importjava.util.HashMap;importjava.util.Map; public class MutableSafeKeyDemo { publicstatic void main(String[] args) { Employee emp = new Employee(2); emp.setName("Robin"); // Put object in HashMap. Map<Employee, String> map = newHashMap<>(); map.put(emp,"Showbasky"); System.out.println(map.get(emp)); // Change Employee name. Change in 'name' has no effect // on hash code. emp.setName("Lily"); System.out.println(map.get(emp)); }} classEmployee { // It is specified while object creation. // Cannot be changed once object is created. No setter for this field. private int id; private String name; publicEmployee(finalint id) { this.id = id; } publicfinal String getName() { return name; } publicfinal void setName(finalString name) { this.name = name; } publicint getId() { return id; } // Hash code depends only on 'id' which cannot be // changed once object is created. So hash code will not change // on object's state change @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + id; return result; } @Override public boolean equals(Object obj) { if(this== obj) return true; if(obj == null) return false; if(getClass() != obj.getClass()) return false; Employee other = (Employee) obj; if(id != other.id) return false; return true; }}
输出:
Showbasky
Showbasky
现在你可能已经理解在HashMap中用可变对象作为Key的危险了。关于本文欢迎提出的任何建议和意见。
- HasnMap中的键
- HasnMap
- HashSet与HasnMap区别和方法
- HashSet与HasnMap区别和方法
- Java中 HashSet与HasnMap区别和方法
- Java中 HashSet与HasnMap区别和方法
- Set和List,HashSet与HasnMap,HashMap详解,HashSet详解
- c#中的组合键
- 关系数据库中的“键”
- Redis中的键查询
- SQL中的外键
- 关系模型中的键
- Vim中的键映射
- Vim中的键映射
- mysql中的外键
- SQLServer中的外键
- postgresql 中的外键
- 数据库中的键
- C语言——数组知识大汇总
- QVariant类
- 创建 event_base
- 搭建匿名FTP
- -weak
- HasnMap中的键
- 探讨android更新UI的几种方法
- Python+client_connection.sendall(http_resp)+TypeError: 'str' does not support the buffer interface
- mac环境python Flask 环境搭建
- linux 添加用户、权限
- ios报错--pie can only be used when targeting iOS 4.2 or later clang: error: linker command failed with
- Linux 常用命令详解
- 让程序员跳槽的非钱原因
- Helloworld