Java hashmap如何保存和查找密钥
我遇到了一个关于HashMap的问题。经过一些没有结果的调试后,我编写了一小段代码来测试Java hashmap如何保存和查找密钥,java,hashmap,Java,Hashmap,我遇到了一个关于HashMap的问题。经过一些没有结果的调试后,我编写了一小段代码来测试HashMap。但结果却更加令人困惑 public static void main(String[] args) { Point a = new Point(0, 0); // java.awt.Point Map<Point, Integer> map = new HashMap<Point, Integer>(); map.put(a,
HashMap
。但结果却更加令人困惑
public static void main(String[] args) {
Point a = new Point(0, 0); // java.awt.Point
Map<Point, Integer> map = new HashMap<Point, Integer>();
map.put(a, 0);
System.out.println(map.containsKey(new Point(0, 0))); // true
a.x = 1;
System.out.println(map.containsKey(new Point(0, 0))); // false
System.out.println(map.containsKey(new Point(1, 0))); // false
System.out.println(map.containsKey(a)); // false
}
publicstaticvoidmain(字符串[]args){
点a=新点(0,0);//java.awt.Point
Map Map=newhashmap();
map.put(a,0);
System.out.println(map.containsKey(新点(0,0));//true
a、 x=1;
System.out.println(map.containsKey(新点(0,0));//false
System.out.println(map.containsKey(新点(1,0));//false
System.out.println(map.containsKey(a));//false
}
我希望第二个或第三个输出可以给我一个真的,第四个肯定是真的。但事实似乎并非如此
关于我想换钥匙的事,我用地图救了一些暴徒。mob有点域,地图的键使用相同的引用。然后,我可以通过协调来寻找暴徒,也可以轻松地更改协调。您可以在中查找并理解它,尽管不像我想的那么容易 问题是,当您更改
x
的值时,会使哈希树中的对象似乎位于错误的位置,我将对此进行说明
将密钥放置在一棵树中,该树如下所示:
.../-- Point(0,0)
root
---\.. nothing
.../.. nothing
root
...\.. Point(1,0)
.../.. Point(1,0)
root
...\.. nothing
如果你把点(1,0)放在里面,它会是这样的:
.../-- Point(0,0)
root
---\.. nothing
.../.. nothing
root
...\.. Point(1,0)
.../.. Point(1,0)
root
...\.. nothing
因此,当您更改密钥时,树如下所示:
.../-- Point(0,0)
root
---\.. nothing
.../.. nothing
root
...\.. Point(1,0)
.../.. Point(1,0)
root
...\.. nothing
现在,您查找点(1,0)
,映射将遍历该键所属的较低分支,但没有任何内容。当你寻找点(0,0)
时,它会穿过上面的分支,那里有错误的键
因此,绝对不要更改对象的.hashCode()
部分的值,这一点很重要。而是使用该对象的新实例进行替换,或者使用对象的克隆放置在HashMap
中
或者,如果您想更改关键点,可以将其从地图中删除,更改它并将其放回。像这样:
public static void main(String[] args) {
Point a = new Point(0, 0); // java.awt.Point
Map<Point, Integer> map = new HashMap<Point, Integer>();
map.put(a, 0);
System.out.println(map.containsKey(new Point(0, 0))); // true
Integer value = map.remove(a);
a.x = 1;
map.put(a,value);
System.out.println(map.containsKey(new Point(0, 0))); // false
System.out.println(map.containsKey(new Point(1, 0))); // true
System.out.println(map.containsKey(a)); // true
}
publicstaticvoidmain(字符串[]args){
点a=新点(0,0);//java.awt.Point
Map Map=newhashmap();
map.put(a,0);
System.out.println(map.containsKey(新点(0,0));//true
整数值=映射。删除(a);
a、 x=1;
map.put(a,值);
System.out.println(map.containsKey(新点(0,0));//false
System.out.println(map.containsKey(新点(1,0));//true
System.out.println(map.containsKey(a));//true
}
您可能希望将remove、alter和put方法转移到对象中自己的方法中,以使其可用。您可以调用它
setAndRelocate(int-newX,int-newY,Map-container)
,并将其返回到常规代码中的一行。由于HashMap的实现方式,您得到的行为是正常的,但会令人困惑
大致上,这里是用键K放置值V的工作原理:
- HashMap计算密钥K的hashcode H
- 在存储值的数组中,H用作索引(必要时进行修剪):
data[H]=条目(K,V)
get(K)
或containsKey(K)
时:
- HashMap计算密钥的哈希代码H
- 然后检查
是否为空,以及它的key是否等于您提供的keydata[H]
- 如果是,则返回值V表示
,或返回值true表示get
containsKey
put
。假设点(0,0)。hashcode()
返回0。因此,该值存储在索引0中:
data = [Point(0, 0), null, ...]
然后修改该点(a.x=1
)。密钥已修改,但HashMap无法检测到它,因此它不会将条目移动到正确的索引
data = [Point(1, 0), null, ...]
之后,map.containsKey(新点(0,0))
返回false,因为根据containsKey
的工作方式,如上所示:
- hashcode返回0(与最初放置时相同)
- 但是,
(您正在测试的密钥)不等于点(0,0)
(您存储的密钥),因此为false点(1,0)
hashcode(点(1,0))
(您正在测试的键)可能会返回一个与hashcode(点(0,0))
(您存储的键)不同的值。假设它返回1,而初始点存储在索引0处。这就是为什么它也返回false
故事的士气:HashMap中使用的键必须是不变的,否则会出现奇怪的行为什么是
点
?它是否有适当的hashCode()
和equals()
实现?此外,切勿修改在映射中用作键的元素点
必须覆盖hashCode()
和equals()
。HashMap
将Point.hashCode()
的值作为键value@drkunibar第一个true是否表示方法已被重写?可能重复