package method; import java.util.HashMap; import java.util.Map; /* * 改写equlas方法时候,总要改写hashCode方法 */ public class OverrideHashCode { public static void main(String[] args) { HashMap<PhoneNumber,String> map = new HashMap<PhoneNumber,String>(); int i=135; double j=2147.123; PhoneNumber phoneNumber1 = new PhoneNumber(i,j,"中国移动"); map.put(phoneNumber1,"jason"); //希望也能取到用户名,两个相等的实例,却哪不到同样的值 //但是取不到,用类为键时候,一定要重写hashCode方法 String username = map.get( new PhoneNumber(i,j,"中国移动")); System.out.println("username: "+username); } } class PhoneNumber{ public final int areaNumber; public final double exchange; public final String extension; public PhoneNumber(int areaNumber, double exchange, String extension) { super(); this.areaNumber = areaNumber; this.exchange = exchange; this.extension = extension; } @Override public boolean equals(Object obj) { if(obj instanceof PhoneNumber){ PhoneNumber p= (PhoneNumber)obj; return p.areaNumber==areaNumber&& p.exchange==exchange&& p.extension==extension; } return false; } /* *如果采用这样的hashCode()方法的类的对象被装入HashMap的话,它们的位置会都在一处,也就是成了一个链表了。 现在知道了为什么一定要改写hashCode,该将如何改写了。书上又给出了一个“处方”: 1)int result = 17; 2)对每个关键域(我觉得就是那些影响equals的域)如下处理: 2.1)int c; 并根据该域的类型: 2.1.1)如果该域f是boolean型,c = (f ? 0 : 1); 2.1.2)如果该域f是byte、char、short、int型,c = (int)f; 2.1.3)如果该域f是long型,c = (f ^ (f >>> 32)); 2.1.4)如果该域f是float型,c = Float.floatToIntBits(f); 2.1.5)如果该域f是double型,c = (int)Double.doubleToLongBits(f); 2.1.6)如果该域f是一个对象,c = f.hashCode(); 2.1.7)如果该域f是一个数组,遍历数组的每个元素,并按2.2)中的做法吧这些散列值组合起来; 2.2)result = 37 * result + c 3)return result * */ @Override public int hashCode() { //return 17; //这样的写法是合法的,因为相等的对象有相同的hashCode值,但是也极为恶劣,因为每个对象多被实例化到同一个散列桶中 //从而散列表变为链表,散列表退化为链表,本该运行时间,变成了平方时间。 int result = 17; result = 37 * result + areaNumber; result = 37 * result + (int)Double.doubleToLongBits(this.exchange); result = 37 * result + this.extension.hashCode(); return result; } }