2.在改写equals的时候总是要改写hashCode (不知道有多少人知道hashCode的作用) 在每个改写了equals方法的类中,必须也要改写hashCode方法。如果不这样的话,就会违反Object.hashCode的通用约定, 这个类就会在所有基于散列值的集合类中无法正常工作,包括HashMap,HashSet和Hashtable 举个例子。 public class MyClass { private int x; private int y; public MyClass() { } public MyClass(int x,int y) { this.x=x; this.y=y; } public boolean equals(Object x) { if (x==null) { return false; } if (!(x instanceof MyClass)) { return false; } MyClass m = (MyClass)x; return m.x==this.x && m.y==this.y; } } Map p = new HashMap(); p.put(new MyClass(33,44),"Test"); 在这个p中,你想通过p.get(new MyClass(33,44))去得到"Test",但实际上返回的是null,因为这个类没有重载hashCode方法,虽然他们使用equals方法会得到true,但这两个实现是放在不同的散列桶里的。 如果给这个类重载hashCode方法,则会得到我们想要的结果,代码如下: public int hashCode() { return 1; } 上面的hashCode方法是合法的,但在实际中,是永远也不会使用的,因为这个方法使所有的对象都得到相同的散列值,每个对象 都会被映射到同一个散列桶中,这个散列表就退化为了链表。那如何能够做一个比较好的散列值呢。按以下的方法做,一般都可 以生成比较好的散列值 1.把某个非零常数值,比如17,保存在一个变量里,比如:int temp=17; 2.对于对象中的每个关键值,完成以下步骤 a.计算每个值的散列码c 1)如果该值是boolean类型,则计算(f?0:1) 2)如果是byte,char,short或者int,则计算(int)f; 3)如果是long,则计算(int)(f^(f>>>32)) 4)如果是float,则计算Float.floatToIntBits(f); 5)如果是一个对象引用,则同样递归调用对象的hashCode. 6)如果是一个数组,则处理每个元素。 b.按照下面公式,把步骤a中计算到的散列码c组合到结果中 temp = 37*temp+c; 所以上面的类实现hashCode方法如下 public int hashCode() { int temp=17; temp = 37*temp+x; temp = 37*temp+y; return temp; } 但在实际中,一些对象的关键值非常多,如果每次调用hashCode()都要经过计算,肯定会费很多资源,如果这样,则可以定义 一个属性值,把计算结果放到这个属性值就可以了。代码如下: private int hashCode = 0; public int hashCode() { if (hashCode==0) { int temp=17; temp = 37*temp+x; temp = 37*temp+y; hashCode = temp; } return hashCode; }
Re: java编程时要遵循的一些原则
最新推荐文章于 2024-09-03 20:34:51 发布