effective Java之【改写equals方法总是要改写hasCode()方法】

       在每一个改写了equals()方法的类中,你必须也要改写hashCode()方法。 不这么做的话 违反了Object.hasCode()的通用约定,从而导致该类无法与所有基于散列值(hash)的集合类结合一起正常运作(如:HashMap HashSet 和HashTable)

 

   java.lang.Object中约定的 hashCode的规范:

 1.一个应用程序执行过程中,一个对象的equals方法所作比较的信息没有被修改的话,那么调用多次hashCode方法返回的应该是同一个整数

2.如果通过equals放比较的两个对象相等 那么 两个对象的hasCode()方法返回的值必须相同

3.比较的两个对象不相同 可以返回相同的hasCode() 但是我们做程序应该尽量保证他们不相同,提高hashtable的性能。。

 

  例子:

写道
public class StaticUserGroupBean {

//要覆盖equals方法必须覆盖hasCode()
@Override
public boolean equals(Object obj) {
StaticUserGroupBean bean = (StaticUserGroupBean)obj;
if(bean.getStepId() == this.stepId &&
bean.getResourceName().equals(this.resourceName)) {
return true;
}
return false;
}
@Override
public int hashCode() {
int result = 11;
int c = getResourceName().hashCode() + getStepId();
return 31*result + c;
}

public String resourceName;
public int actionId;
public boolean isUser;
public int stepId;
public String getResourceName() {
return resourceName;
}
public void setResourceName(String resourceName) {
this.resourceName = resourceName;
}
public int getActionId() {
return actionId;
}
public void setActionId(int actionId) {
this.actionId = actionId;
}
public boolean isUser() {
return isUser;
}
public void setUser(boolean isUser) {
this.isUser = isUser;
}
public int getStepId() {
return stepId;
}
public void setStepId(int stepId) {
this.stepId = stepId;
}
}

 

 

 

这里重写了hashCode()散列函数,刚开始重写这个hasCode()方法的时候 我不知道如何去设计这个方法该返回什么值,根据一个好的散列函数的倾向:【为不相等的对象产生不同的散列码(hashCode)】..我抄袭了下一个简单的通用方法,当然可以自己设计:

 

   1.把某个非零证书,比如这里的11  保存到一个result 的int变量中 (这个result就是用来组装最后返回的散列值的)

   2.对于对象中每一个关键域(即equals方法中的进行比较的域 上例中的stepId和ResouceName)完成下面的操作:

     a.进行散列值的计算 c :

          i:boolean 类型的 f?0:1.

          byte char short 或者int行的 直接就是 (int)f

         long类型的(int)(f^(f>>>32)) 

         float >> Float.floatToIntBits(f)

        double>>(int)(Double.doubleToLongBits(f)^(Double.doubleToLongBits(f)>>>32))

       如果是引用对象 如:String 直接或者别的类型 直接返回对象的 hasCode()方法,因此要记得引用对象也要有相应的hasCode()方法的重写  String类型的话 简单的调用下 String.hasCode()方法。

     如果是数组的方法 循环每一个元素 按照上面给出来的规则去改写。

 3.return 37*result + c;

完成了这个方法之后  多检查几遍   是否相等的对象具有相等的hasCode。。

 

 上面出示话得值 11 是随便给的 可以根据自己的需要给出  为什么要给一个非零的初始值??我也不太明白 据说是可以避免一定的散列冲突。

 

 

其实上面那些我开始也不知道有啥用处,不就是判断是不是相等吗,有什么用吗?  其实挺有用的 比如:

   我们要去除List中的一些对象的重复值(当然这个重复的标准由你的equals方法去确定)  你会怎么去做 ??

 

 我们可以通过Set的特性,即没有重复的值 来快速进行去重复操作,而HashSet判断对象是否重复的标准就是equals()方法和hashCode()。所以重写hashCode()方法:

 

public class Test {
	
	public static void main(String[] args) {
		
		List list = new ArrayList();
		
		StaticUserGroupBean bean1  = new StaticUserGroupBean();
		bean1.setActionId(1);
		bean1.setResourceName("aaa");
		bean1.setStepId(2);
		bean1.setUser(false);
		
		StaticUserGroupBean bean2  = new StaticUserGroupBean();
		bean2.setActionId(1);
		bean2.setResourceName("aaa");
		bean2.setStepId(3);
		bean2.setUser(false);
		
		list.add(bean1);
		list.add(bean2);
		
		System.out.println(bean1.hashCode());
		System.out.println(bean2.hashCode());
		System.out.println(bean1.equals(bean2));
		list = removeCopys(list);
		for(int i = 0 ; i < list.size() ; i ++) {
			StaticUserGroupBean bean = (StaticUserGroupBean)list.get(i);
			System.out.println(bean.getActionId()  + "   " + bean.getResourceName() +  "   " + 
					bean.getStepId());
		}
	}
	
       //利用set的特性去除重复项  
	private static List removeCopys(List list) {
		Set set = new HashSet(list);    
                //把list清空 
		list.clear();  
               //再把去掉了重复值的list添加进来  
		list.addAll(set);    
		return list;
	}
}
 

 

你可能感兴趣的:(java,C++,c,bean,F#)