首页 > 代码库 > java 翻盖hashCode()深入探讨 代码示例

java 翻盖hashCode()深入探讨 代码示例

java 翻盖hashCode()深入探讨 代码示例

package org.rui.collection2.hashcode;
/**
 * 覆盖hashcode
 * 设计HashCode时最重要的因素 就是:无论何时,对同一个对象调用HashCode都应该产生同样的值,
 * 如果你的HashCode方法依赖于对象中易变的数据,用户就要当心了,因为此数据发生变化 时
 * HashCode就会生成一个不同的散列码,相当于产生一个不同的健
 * 此外 也不应该使HashCode依赖于具有唯一性的对象信息,尤其是使用this的值,这只能很糟糕,
 * 因为这样做无法生成一个新的健,使这与Put中原始的健值对中的健相同,它的默认的HashCode使用的是对象的地址
 * 所以 应该 使用对象内有意义的识别信息
 * 
 * 以下以String类为例 String对象都 映射到同一块内存域,
 *  所以 new String("hello") 生成的两个实例 ,虽然是相互独立的,
 *  但是对它们使用HashCode应该生成同样的结果,以下示例可以看到 
 *  对String而言,HashCode明显是基于String的内容的,
 *  
 *  因此 要想使HashCode实用,它必须 速度快,并且必须有意义。也就是说,它必须基于对象的内容生成的散列码,
 *  记得吗,散列码不必是独一无二的 (应该更关注生成速度,而不是唯一性)
 *  但HashCode和Equals 必须能够完全确定对象的身份
 *  所以散列码生成的范围并不重要,只要是int即可
 *  还有别一个影响因素,好的HashCode应该产生分布均匀的散列码
 *  
 *  
 * @author lenovo
 *
 */

public class StringHashCode {
	public static void main(String[] args) {
		String[] hello="Hello Hello".split(" ");
		System.out.println(hello[0].hashCode());
		System.out.println(hello[1].hashCode());
	}
}
/**output:
69609650
69609650
*/

package org.rui.collection2.hashcode;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * 覆盖hashcode
 * 
 * 在Effective java programming language guide ....这本书 为怎样写出一份像样的hashcode给出了基本指导
 *  1,int变量result 赋予某个非零值 常 量,
 *  2,为对象内每个有意义的域f(即每个可以做equlas操作的域) 计算一个int散列码c
 *  ----------------------------------------- -----------------------------------------
 *  域类型                                                   计算
 *  ----------------------------------------- -----------------------------------------
 *  boolean                  c=(f?0:1)
 *  byte,char,shor或int       c=(int)f
 *  long                     c=(int)(f^(f>>>32))
 *  float                    c=Float.floatToIntBits(f);      根据 IEEE 754 浮点“单一格式”位布局,返回指定浮点值的表示形式
 *  double                   c=Double.doubleToLongBits(f);  
 *  Object 其equals调用这个域的equlas          c=f.hashCode();
 *  数组                                                      对每个元素应用上述规则
 *  
 *  3,合并计算得到的散列码
 *  4,返加result
 *  5检查hashcode最后生的结果。确保相同的地象有相同的散列码
 *   ----------------------------------------- -----------------------------------------
 *  
 *  
 * CountedString是由一个String和id组成,此id代表包含相同String的CountedString对象的编号
 * 所有的String被存储在ArrayList中,在构造器中通过迭代遍历此ArrayList完成对Id的计算
 * 
 * hashcode and equals都是基于CountedString的两 个域来生成的结果,如果它们只是基于String或只基于Id
 * 不同的对象就可能产生相同的值
 * 
 * 在Main中使用了相同的String,创建了多个CountedString对象,这说明,虽然String相同 ,
 * 但由于Id不同,所以使得它们的散列码并不相同,
 * @author lenovo
 *
 */
public class CountedString {
	private static List<String> created = new ArrayList<String>();
	private String s;
	private int id = 0;

	public CountedString(String str) {
		s = str;
		created.add(s);
		// id is the total numbe of instances
		// of this string in by CountedString
		for (String s2 : created) {
			if (s2.equals(s))
				id++;
		}
	}

	public String toString() {
		return "String:" + s + "  id:" + id + " hashCode:" + hashCode();
	}
	
	public int hashCode()
	{
		//the very simple approach
		//return s.hashCode()*id;
		//using joshua bloch's recipe//使用joshua bloch的配方
		int result=17;
		//合并计算得到散列码
		result=37*result+s.hashCode();
		result=37*result+id;
		return result;
	}
	
	public boolean equals(Object o) {
		return o instanceof CountedString&&
				s.equals(((CountedString)o).s)&&
				id==((CountedString)o).id;

	}
	public static void main(String[] args) {
		Map<CountedString,Integer> map=new HashMap<CountedString,Integer>();
		CountedString[] cs=new CountedString[5];
		for(int i=0;i<cs.length;i++)
		{
			cs[i]=new CountedString("hi");
			map.put(cs[i], i);//autobox int->Integer			
		}
		System.out.println(map);
		for(CountedString cstring:cs)
		{
			System.out.println("Looking up"+cstring);
			System.out.println("map.get(cstring):"+map.get(cstring));
		}
	}

}

package org.rui.collection2.hashcode;
/**
 * 覆盖hashCode
 * 
 * compareTo 方法有一个比较结构,因此它会产生一个排序序列,排序的规则首先按照实际类型排序
 * 然后如果有名字的话,按照name排序,最后按照创建的顺序排序,
 * @author lenovo
 *
 */
public class Individual implements Comparable<Individual>{

	private static long counter=0;
	private final long id=counter++;
	private String name;
	
	public Individual(String name){this.name=name;}
	public Individual(){}
	public String toString(){
		return getClass().getSimpleName()+
				(name==null?"":" "+name);
	}
	public long id(){return id;}
	public boolean equals(Object o){
		return o instanceof Individual&&
				id==((Individual)o).id;
	}
	public int hashCode(){
		int result=17;
		if(name!=null)
			result=37*result+name.hashCode();
			result=37*result+(int)id;
		return result;
	}
	@Override
	public int compareTo(Individual o) {
		String first=getClass().getSimpleName();
		String argFirst=o.getClass().getSimpleName();
		int firstCompare=first.compareTo(argFirst);
		if(firstCompare!=0)
		{
			return firstCompare;
		}
		if(name!=null && o.name!=null)
		{
			int secondCompare=name.compareTo(name);
			if(secondCompare!=0)
				return secondCompare;
		}
		
		return (o.id<id?-1:(o.id==id?0:1));
	}

}

package org.rui.collection2.hashcode;

import java.util.*;

import org.rui.classts.Pet;
import org.rui.classts.chilnd.*;

/**
 * 
 * 下面的示例说明了它如何工作的;
 * 
 * 由于所有的寵物都有名字,因此它們首先按照類型排序,然后在同類型中按照 名字排序
 * 為新類編寫正確的hashCode和equals很需要技巧,Apache的jakarta commons項目中有許多工具可以人幫助你完成此事
 * @author lenovo
 *
 */

public class IndvidualTest {

	public static void main(String[] args) {
		//Set<Individual> pets=new TreeSet<Individual>();
		Pet p=new Cat("猫");
		Pet p1=new Dog("狗");
		Pet p2=new EgyptianMan("EgyptianMan");
		Pet p3=new Manx("马恩岛猫");
		Pet p4=new Pug("巴哥犬");
	
		//一个人有很多宠物
		Map<Individual,List<? extends Pet>> list2=new HashMap<Individual,List<? extends Pet>>(); 
		
		Individual in=new Individual("Dawn");
		Individual in2=new Individual("東方不敗");
		list2.put(in, Arrays.asList(p,p1,p2,p3,p4));
		list2.put(in2, Arrays.asList(p2,p3,p4));
		
		System.out.println(list2);//輸出這個人的寵物
		
		//查找Dawn的寵物
		List<? extends Pet> l=list2.get(in);
		System.out.println(l);
		
		
	}
}
/**output:
{Individual 東方不敗=[Pet [name=EgyptianMan], Pet [name=马恩岛猫], Pet [name=巴哥犬]],
 Individual Dawn=[Pet [name=猫], Pet [name=狗], Pet [name=EgyptianMan], Pet [name=马恩岛猫], Pet [name=巴哥犬]]}
[Pet [name=猫], Pet [name=狗], Pet [name=EgyptianMan], Pet [name=马恩岛猫], Pet [name=巴哥犬]]
 */