问题描述
最近,我在我们的代码库中研究一个bug,我发现通过String查找HashMap中的值会产生正确的结果,而使用$ {key}查找GStringImpl的值会产生不正确的结果(null )结果。以下是我在Groovy控制台中进行的测试:
def myMap = [testString:value]
def testString =testString
println myMap.get($ {testString})
println myMap [testString]
println$ {testString}。getClass()
println testString.getClass()
String myString =test
def myGroovyString =$ {myString}
println myString.equals(myGroovyString)
println myString.hashCode()
println myGroovyString.hashCode()
println myString.compareTo(myGroovyString)
产出如下:
null
值
class org.codehaus.groovy.runtime.GStringImpl
class java.lang.String
false
3556498
3556535
0
$ c $现在,如果我将映射的定义更改为TreeMap的实现,如下所示:
$ b b $ b
def myMap = [testString:value] as TreeMap
我得到以下结果:
value
value
class org.codehaus.groovy.runtime.GStringImpl
class java.lang.String
false
3556498
3556535
0
据我所知,这种情况发生的原因可能是因为(我没有看HashMap与TreeMap的实现)HashMap通过hashCode()查找关键字,而TreeMap将使用compareTo(...)。我的问题是为什么String和GStringImpl不会生成相同的hashCode(),并且在使用equals(...)时不会生成真正的结果?这是一个错误/设计错误?还是这样做是有原因的?看起来这些方法的结果应该是兼容的,因为这些类之间的交互应该对程序员是无缝的。这样做的结果是代码中出现错误的巨大潜力,可能起初看起来很直观,但会导致地图查找中的错误。
谢谢,
Chris 解决方案 LinkedHashMap
Groovy中的默认 Map
类型)根据对象的 hashCode
执行查找。
TreeMap
在树的根上执行 compareTo
调用,然后关闭根据此结果向左或向右分支(并返回值,如果 key.compareTo(node.key)
返回 0 $
正如您所见
println myString .compareTo(myGroovyString)
打印 0
。这就是为什么该项目在 TreeMap
中找到的原因,而不同的 hashCode
是为什么它在 LinkedHashMap
Groovy字符串不是字符串,它们是模板机制和完全不同的对象。这就是为什么你得到不同的结果 hashCode
- 请参阅
Recently, I was working in our codebase on a bug where I found that looking up a value in a HashMap by String produced the correct result whereas looking up a value by GStringImpl using "${key}" produced an incorrect (null) result. The following is a test I did in the Groovy console:
def myMap = ["testString" : "value"]
def testString = "testString"
println myMap.get("${testString}")
println myMap[testString]
println "${testString}".getClass()
println testString.getClass()
String myString = "test"
def myGroovyString = "${myString}"
println myString.equals(myGroovyString)
println myString.hashCode()
println myGroovyString.hashCode()
println myString.compareTo(myGroovyString)
the output produced was the following:
null
value
class org.codehaus.groovy.runtime.GStringImpl
class java.lang.String
false
3556498
3556535
0
Now, if I change the definition of the map to be an implementation of TreeMap such as the following:
def myMap = ["testString" : "value"] as TreeMap
I get the following result:
value
value
class org.codehaus.groovy.runtime.GStringImpl
class java.lang.String
false
3556498
3556535
0
I understand that the reason why this happens is probably because (I did not look at the implementation of HashMap vs. TreeMap) HashMap looks up a key by hashCode() whereas TreeMap is going to use compareTo(...). My question is why do String and GStringImpl not produce the same hashCode() and not produce a true result when equals(...) is used? Is this a bug/design error? Or was this done for a reason? It seems the results of these methods should be compatible since interactions between these classes are supposed to be seamless to the programmer. The result of this is a huge potential for mistakes in code that might seem intuitive at first but results in a bug in map lookups.
Thanks,
Chris
解决方案 LinkedHashMap
(the default Map
type in Groovy) performs a lookup based on the hashCode
of the object.
TreeMap
performs a compareTo
call on the root of the tree, and goes off down the left or right branch depending on the result of this (and returns the value if key.compareTo( node.key )
returns 0
)
As you have seen
println myString.compareTo(myGroovyString)
prints 0
. This is why the item is found in the TreeMap
, and the different hashCode
is why it is not found in the LinkedHashMap
Groovy Strings are not Strings, they are a templating mechanism and a completely different object. This is why you get different results for hashCode
-- see the 'GStrings aren't Strings' section on this page
这篇关于GroovyString hashCode和equals不计算为与String相同的值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!