84669 Lernen von Personen
152542 Lernen von Personen
20005 Lernen von Personen
5487 Lernen von Personen
7821 Lernen von Personen
359900 Lernen von Personen
3350 Lernen von Personen
180660 Lernen von Personen
48569 Lernen von Personen
18603 Lernen von Personen
40936 Lernen von Personen
1549 Lernen von Personen
1183 Lernen von Personen
32909 Lernen von Personen
光阴似箭催人老,日月如移越少年。
实现hashCode方法的通用约定
hashCode
在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这个同一对象调用多次,hashCode方法必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。 如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。反之,如果两个对象hashCode方法返回整数结果一样,则不代表两个对象相等,因为equals方法可以被重载。 如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但,如果能让不同的对象产生不同的整数结果,则有可能提高散列表的性能。
在应用程序的执行期间,只要对象的equals方法的比较操作所用到的信息没有被修改,那么对这个同一对象调用多次,hashCode方法必须始终如一地返回同一个整数。在同一个应用程序的多次执行过程中,每次执行所返回的整数可以不一致。
equals
如果两个对象根据equals(Object)方法比较是相等的,那么调用这两个对象中任意一个对象的hashCode方法都必须产生同样的整数结果。反之,如果两个对象hashCode方法返回整数结果一样,则不代表两个对象相等,因为equals方法可以被重载。
equals(Object)
如果两个对象根据equals(Object)方法比较是不相等的,那么调用这两个对象中任意一个对象的hashCode方法,则不一定要产生不同的整数结果。但,如果能让不同的对象产生不同的整数结果,则有可能提高散列表的性能。
hashCode散列码计算(来自:Effective Java)
把某个非零的常数值,比如17,保存在一个名为result的int类型的变量中。 对于对象中每个关键域f(指equals方法中涉及的每个域),完成以下步骤: 为该域计算int类型的散列码c: 如果该域是boolean类型,则计算(f?1:0)。 如果该域是byte,char,short或者int类型,则计算(int)f。 如果该域是long类型,则计算(int)(f^(f>>>32))。 如果该域是float类型,则计算Float.floatToIntBits(f)。 如果该域是double类型,则计算Double.doubleToLongBits(f),然后按照步骤2.1.3,为得到的long类型值计算散列值。 如果该域是一个对象引用,并且该类的equals方法通过递归地调用equals的方式来比较这个域,则同样为这个域递归地调用hashCode。如果需要更复杂的比较,则为这个域计算一个范式(canonical representation),然后针对这个范式调用hashCode。如果这个域的值为null,则返回0(其他常数也行)。 如果该域是一个数组,则要把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2.2中的做法把这些散列值组合起来。如果数组域中的每个元素都很重要,可以利用发行版本1.5中增加的其中一个Arrays.hashCode方法。 按照下面的公式,把步骤2.1中计算得到的散列码c合并到result中:result = 31 * result + c; //此处31是个奇素数,并且有个很好的特性,即用移位和减法来代替乘法,可以得到更好的性能:`31*i == (i<<5) - i, 现代JVM能自动完成此优化。 返回result 检验并测试该hashCode实现是否符合通用约定。
把某个非零的常数值,比如17,保存在一个名为result的int类型的变量中。
17
result
int
对于对象中每个关键域f(指equals方法中涉及的每个域),完成以下步骤:
f
为该域计算int类型的散列码c:
如果该域是boolean类型,则计算(f?1:0)。
boolean
f?1:0
如果该域是byte,char,short或者int类型,则计算(int)f。
byte
char
short
(int)f
如果该域是long类型,则计算(int)(f^(f>>>32))。
long
(int)(f^(f>>>32))
如果该域是float类型,则计算Float.floatToIntBits(f)。
float
Float.floatToIntBits(f)
如果该域是double类型,则计算Double.doubleToLongBits(f),然后按照步骤2.1.3,为得到的long类型值计算散列值。
double
Double.doubleToLongBits(f)
如果该域是一个对象引用,并且该类的equals方法通过递归地调用equals的方式来比较这个域,则同样为这个域递归地调用hashCode。如果需要更复杂的比较,则为这个域计算一个范式(canonical representation),然后针对这个范式调用hashCode。如果这个域的值为null,则返回0(其他常数也行)。
(canonical representation)
null
0
如果该域是一个数组,则要把每一个元素当做单独的域来处理。也就是说,递归地应用上述规则,对每个重要的元素计算一个散列码,然后根据步骤2.2中的做法把这些散列值组合起来。如果数组域中的每个元素都很重要,可以利用发行版本1.5中增加的其中一个Arrays.hashCode方法。
Arrays.hashCode
按照下面的公式,把步骤2.1中计算得到的散列码c合并到result中:result = 31 * result + c; //此处31是个奇素数,并且有个很好的特性,即用移位和减法来代替乘法,可以得到更好的性能:`31*i == (i<<5) - i, 现代JVM能自动完成此优化。
c
result = 31 * result + c
31
返回result
检验并测试该hashCode实现是否符合通用约定。
示例实现
@Override public int hashCode() { int result = 17; result = 31 * result + (origin == null ? 0 : origin.hashCode()); result = 31 * result + (hsNumber == null ? 0 : hsNumber.hashCode()); result = 31 * result + (imageUrl == null ? 0 : imageUrl.hashCode()); result = 31 * result + (classificationName == null ? 0 : classificationName.hashCode()); return result; }
java的int固定为32位。另外你的latitude和longtitude是double..我觉得会是64位。
hashcode 和equals 这两方法是有约定的语义的,你可以看一下 Object
你写的那个equals我觉得可以用。
注意: Object类中的约定其实是个很弱的约束。我们可以写出这样的hashcode()和equals()而不违反约定;
public int hashcode() { return 0; } public boolean equals(Object o) { return (o != null) && (o.getClass() == getClass()); }
所以真正的问题在于 你如何定义相等。代码是次要的。如果定义相等为"经度和纬度分别相等",那么你给的代码是一个可以用的方案 (但不是唯一的可用方案)。
实现
hashCode
方法的通用约定hashCode
散列码计算(来自:Effective Java)示例实现
java的int固定为32位。另外你的latitude和longtitude是double..我觉得会是64位。
hashcode 和equals 这两方法是有约定的语义的,你可以看一下 Object
你写的那个equals我觉得可以用。
注意: Object类中的约定其实是个很弱的约束。我们可以写出这样的hashcode()和equals()而不违反约定;
所以真正的问题在于 你如何定义相等。代码是次要的。
如果定义相等为"经度和纬度分别相等",那么你给的代码是一个可以用的方案 (但不是唯一的可用方案)。