java.lnag.Object中对hashCode的约定:
- 在一个应用程序执行期间,如果一个对象的equals方法做比较所用到的信息没有被修改的话,则对该对象调用hashCode方法多次,它必须始终如一地返回同一个整数。
- 如果两个对象根据equals(Object o)方法是相等的,则调用这两个对象中任一对象的hashCode方法必须产生相同的整数结果。
- 如果两个对象根据equals(Object o)方法是不相等的,则调用这两个对象中任一个对象的hashCode方法,不要求产生不同的整数结果。但如果能不同,则可能提高散列表的性能。
看个不改写hashCode导致使用hashMap不能出现预期结果的例子:
public final class PhoneNumber{
private final short areaCode;
private final short exchange;
private final short extension;
public PhoneNumber(int areaCode,int exchage,int extension){
rangeCheck(areaCode,999,"area code");
rangeCheck(exchange,999,"exchange");
rangeCheck(extension,9999,"extension");
this.areaCode=(short) areaCode;
this.exchange=(short) exchange;
this.extension=(short)extension;
}
private static void rangeCheck(int arg,int max, String name){
if(arg<0 || arg>max) throw new IllegalArgumentException(name+":"+arg);
}
public boolean equals(Object o){
if (o == this) reutrn true;
if (!(o instanceof PhoneNumber)) return false;
PhoneNumber pn=(PhoneNumber)o;
return pn.extension==extension && pn.exchange=exchange && pn.areaCode=areaCode;
}
//No hashCode method
...
}
现在有以下几行程序:
Map m=new HashMap();
m.put(new PhoneNumber(1,2,3),"Jenny");
则m.get(new PhoneNumber(1,2,3))的返回值什么?
虽然这个实例据equals是相等的,但由于没改写hashCode而致两个实例的散列码并不同(即违反第二条要求),因则返回的结果是null而不是"Jenny".
理想情况下,一个散列函数应该把一个集合中不相等的实例均匀地分布到所有可能的散列值上,下面是接近理想的“处方”:
- 把某个非零常数值(如17)保存在一个叫result的int类型的变量中;
- 对于对象中每个关键字域f(指equals方法中考虑的每一个域),完成以下步骤:
- 为该域计算int类型的散列码c:
- 如果该域是bloolean类型,则计算(f?0:1)
- 如果该域是byte,char,short或int类型,则计算(int)f
- 如果该域是long类型,则计算(int)(f^(>>>32))
- 如果该域是float类型,则计算Float.floatToIntBits(f)
- 如果该域是double类型,则计算Double.doubleToLongBits(f)得一long类型值,然后按前述计算此long类型的散列值
- 如果该域是一个对象引用,则利用此对象的hashCode,如果域的值为null,则返回0
- 如果该域是一个数组,则对每一个数组元素当作单独的域来处理,然后安下一步的方案来进行合成
- 利用下面的公式将散列码c 组合到result中。result=37*result+c;
- 检查“相等的实例是否具有相等的散列码?”,如果为否,则修正错误。
依照这个处方,得PhoneNumber的hashCode方法:
public int hashCode(){
int result=17;
result=37*result+areaCode;
result=37*result+exchange;
result=37*result+extension;
return result;
}
如果计算散列码的代价比较高,可以考虑用内部保存这个码,在创建是生成或迟缓初始化生成它。不要试图从散列码计算中排除掉一个对象的关键部分以提高性能。
分享到:
相关推荐
2、为什么改写equals()的时候,总是要改写hashCode() 两个原则: hashCode()的返回值和equals()的关系如下: 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。 如果x.equals(y)返回...
11. 如果重写了 `myObject` 的 `equals()` 方法,下列哪个方法可能改写?答案是 `hashCode()` 方法,因为 `equals()` 方法和 `hashCode()` 方法是相关的。 12. 下列哪些是数据库中存储过程使用的参数?答案是 `...
6. **hashCode()与equals()的关系** - 如果两个对象的hashCode()相同,这并不意味着它们的equals()也一定为true。根据哈希码相同只代表可能存在冲突,但实际内容可能不同。 7. **final关键字的作用** - final修饰...
Java中有个Object 类,是所有Java 类的继承根源,其内声明了数个应该在所有Java 类中被改写的方法:hashCode、equals、clone、toString、getClass等。其中getClass返回一个Class 对象。Class对象十分特殊。他是...
为了正确处理这些变化,`hashCode`和`equals`函数也被相应地更新。 在解析SQL的过程中,`SelectSQLAnalyser`类的`analyseWhereCondition`和`tryColumnCondition`函数得到了增强,新增了对`BetweenOperatorNode`的...
- **生成hashCode()和equals()方法**:右键 -> `Source` -> `Generate hashCode() and equals()`。 #### 五、编辑 - **全局查找并替换**:`Ctrl + F` - **文本编辑器查找上一个**:`Ctrl + Shift + K` - **文本编辑...
- 提供了一些基本方法,如`toString()`, `equals()`, `hashCode()`等。 **7.10 封装类** - 用于封装基本类型的数据和与之相关的操作。 **7.11 内部类** - **内部类的分类**:成员内部类、局部内部类、静态内部类...
// 每次 a 的下一项都等于前一项*10,再加上刚输入时的 a ;注意,这时的 a 已经变化了。 } System.out.println("sum="+sum); } } 8、求 2/1+3/2+5/3+8/5+13/8.....前20项之和? class Sum{ public static ...