В чем разница между `##` и `hashCode`?
В чем разница между методами ##
и hashCode
?
Кажется, что они выводят одни и те же значения независимо от того, какой класс или перегрузка hashCode
я использую. Google не помогает, так как он не может найти символ ##
.
Ответы
Ответ 1
"Подклассы" AnyVal
ведут себя неправильно с точки зрения хэширования:
scala> 1.0.hashCode
res14: Int = 1072693248
Конечно, это связано с призывом к:
scala> new java.lang.Double(1.0).hashCode
res16: Int = 1072693248
Мы можем предпочесть:
scala> new java.lang.Double(1.0).##
res17: Int = 1
scala> 1.0.##
res15: Int = 1
Мы должны ожидать этого, учитывая, что int
1 также является double
1. Конечно, эта проблема не возникает в Java. Без этого у нас была бы эта проблема:
Set(1.0) contains 1 //compiles but is false
К счастью:
scala> Set(1.0) contains 1
res21: Boolean = true
Ответ 2
##
, потому что hashCode
не согласуется с оператором ==
в Scala. Если a == b
, то a.## == b.##
независимо от типа a и b (если пользовательские реализации hashCode
верны). То же самое не относится к hashCode
, как это видно из примеров, представленных другими плакатами.
Ответ 3
Просто хочу добавить к ответам других плакатов, что, хотя метод ## стремится сохранить контракт между равенствами и хэш-кодами, в некоторых случаях он, по-видимому, недостаточно хорош, например, когда вы сравниваете удвоения и длинные (scala 2.10.2):
> import java.lang._
import java.lang._
> val lng = Integer.MAX_VALUE.toLong + 1
lng: Long = 2147483648
> val dbl = Integer.MAX_VALUE.toDouble + 1
dbl: Double = 2.147483648E9
> lng == dbl
res65: Boolean = true
> lng.## == dbl.##
res66: Boolean = false
> (lng.##, lng.hashCode)
res67: (Int, Int) = (-2147483647,-2147483648)
> (dbl.##, dbl.hashCode)
res68: (Int, Int) = (-2147483648,1105199104)