我有以下情况。我有一个Java中的HashMap,键作为字符串。 然后在某个阶段,在运行时我创建等于这些键的字符串,以便从该映射中检索数据。字符串在“for”循环中创建如下:
String keyToRetrive = "lights[" + Integer.toString(i) + "]" + ".Intensity";
奇怪之处在于,当我遍历地图找到等于该字符串的键时,即使找到匹配项,搜索步骤也会结束。所以在此搜索循环中:
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
if (name == entry.getKey()) { ///name- "lights[0].Intesity"
uniformOut = (ICleanable) entry.getValue();
break;
}
}
名称为“lights [0] .Intesity”的键永远不会返回true,即使地图包含一个。我如何解决它。我使用了hashCode()来比较两个字符串值。所以这个版本确实有效:
while (iter.hasNext()) {
Map.Entry entry = (Map.Entry) iter.next();
if (name.hashCode() == entry.getKey().hashCode()) {
uniformOut = (ICleanable) entry.getValue();
break;
}
}
更新:在指出“==”不能正常工作并且应该使用“equals()”的事实后,我想缩小这个问题:为什么“==”对于不是的字符串有效从几个连接块创建?我的意思是,如果我定义键字符串以将其再次比较为简单的单个字符串:
String foo="foo";
这样的字符串可以使用“==”与HashMap键进行比较。
我不是专业的Java程序员,所以任何人都可以解释为什么它会这样运作?
答案 0 :(得分:8)
您正在使用==
运算符比较字符串。请改用equals()
:
name.equals(entry.getKey())
这是Java中常见的陷阱,请参阅How do I compare strings in Java?和Difference between Equals/equals and == operator?。
toString()
,所以:
"lights[" + Integer.toString(i) + "]" + ".Intensity"
可以替换为:
"lights[" + i + "]" + ".Intensity"
它适用于任何类型的i
,而不仅仅是int
。
答案 1 :(得分:5)
使用==
比较对象时,您正在执行“引用相等”比较,这意味着您正在检查两个引用是否指向同一个{ {1}}内存中的对象。如果你熟悉C,那就像是:
String
另一方面,当您使用char* a = some_string();
char* b = some_other_string();
if (a == b) { ... }
比较对象时,您正在执行“结构相等”比较,这意味着您正在检查这两个对象是否包含等效数据。同样,C的类比是:
.equals()
现在,你真的,真的不想做的事情是比较两个对象的哈希码。为什么不?因为具有相同哈希码的两个对象不一定相等!它们可能是,但你不能正确地依赖它。
更新:您还询问了char* a = some_string();
char* b = some_other_string();
if (strcmp(a, b) == 0) { ... }
为什么适用于字符串文字。答案是因为Java编译器不在堆上分配常量字符串;相反,它将它们存储在使用它们的类的常量池中。所以,如果你写:
==
然后编译器将两个引用指向类的常量池中的相同位置。但是,如果你写:
String foo1 = "foo";
String foo2 = "foo";
编译器不够聪明,无法确定String foobar1 = "foobar";
String foobar2 = "foo" + bar();
String bar() { return "bar"; }
在逻辑上等同于foobar2
。但是,即使您知道这两个变量是编译时常量,仍然应该保持简单并使用foobar1
。
答案 2 :(得分:0)
其他人已经说明了为什么你的代码不起作用,但是:
1)如果你正在使用HashMap,你应该使用map.get(key)来检索值,而不是条目的交互者;这就是哈希地图的重点。
2)使用泛型,避免尽可能多地明确施放!