hashcode()是干什么用的:
hashCode 的常规协定是:
· 在 Java 应用程序执行期间,在同一对象上多次调用hashCode 方法时,必须一致地返回相同的整数,前提是对象上 equals比较中所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
· 如果根据 equals(Object)方法,两个对象是相等的,那么在两个对象中的每个对象上调用 hashCode 方法都必须生成相同的整数结果。
· 以下情况不 是必需的:如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么在两个对象中的任一对象上调用hashCode 方法必定会生成不同的整数结果。但是,程序员应该知道,为不相等的对象生成不同整数结果可以提高哈希表的性能。
实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。)
Equals():注意:当此方法被重写时,通常有必要重写hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
其源代码:
public boolean equals(Object obj) {
return (this == obj);
注:判读两个对象是否相等;
总的来说,Java中的集合(Collection)有两类,一类是List,再有一类是Set。你知道它们的区别吗?前者集合内的元素是有序的,元素可以重复;后者元素无序,但元素不可重复。那么这里就有一个比较严重的问题了:要想保证元素不重复,可两个元素是否重复应该依据什么来判断呢?这就是Object.equals方法了。但是,如果每增加一个元素就检查一次,那么当元素很多时,后添加到集合中的元素比较的次数就非常多了。也就是说,如果集合中现在已经有1000个元素,那么第1001个元素加入集合时,它就要调用1000次equals方法。这显然会大大降低效率。
于是,Java采用了哈希表的原理。哈希(Hash)实际上是个人名,由于他提出一哈希算法的概念,所以就以他的名字命名了。哈希算法也称为散列算法,是将数据依特定算法直接指定到一个地址上。如果详细讲解哈希算法,那需要更多的文章篇幅,我在这里就不介绍了。初学者可以这样理解,hashCode方法实际上返回的就是对象存储的物理地址(实际可能并不是) }
在实际的应用当中你也许会重新equals() 方法,若不重新hashcoade()方法比如下面的程序:
publicclass HashObject
{
private String name = null;
public static int hascode = 0;
private int temp = 0;
public HashObject()
{
hascode++;
if(temp <= 0)
{
temp = hascode;
}
}
public String getName()
{
returnname;
}
public void setName(Stringname)
{
this.name = name;
}
@Override
public int hashCode()
{
returntemp;
}
@Override
public boolean equals(Objectobj)
{
returnhascode % 2 == 0;
}
public static void main(String[]args)
{
HashObject obj1 = new HashObject();
obj1.setName("Lilei");
HashObject obj2 = new HashObject();
obj2.setName("Hanmeimei");
Map<HashObject,HashObject> test = new HashMap<HashObject,HashObject>();
test.put(obj1, obj1);
test.put(obj2, obj2);
test.get(obj1);
System.out.println("equals is " + obj2.equals(obj1));
System.out.println("obj2's hashCode = " + obj2.hashCode());
System.out.println("obj1's hashCode = " + obj1.hashCode());
System.out.println(test.get(obj1));
System.out.println(test.get(obj2));
Set<HashObject> set = new HashSet<HashObject>();
set.add(obj1);
set.add(obj2);
System.out.println(set);
}
@Override
public String toString()
{
return"HashObject.toString():" + getName() + " HashCode = " +hashCode();
}
}
运行结果:
equals is true
obj2's hashCode = 2
obj1's hashCode = 1
HashObject.toString():Lilei HashCode = 1
HashObject.toString():Hanmeimei HashCode = 2
[HashObject.toString():Lilei HashCode = 1,HashObject.toString():Hanmeimei HashCode = 2]
是可以出现equals()相等 到hashcode 不相同,但是会发生如下
例子:equals相等但是hashcode不等(即重写了equals不重写hashcode方法的坏处):
Set<A> set = new HashSet<A>();
set.put(a1);
set.put(a2);
如果a1.equals(a2)返回true,那么我们认为“a1和a2即为同一对象”,把它两放到set中去就只能存下一个对象,因为Set不允许重复的对象。Set存元素时使用对象的hashCode决定存储的位置,这样调用a1和a2的hashCode()方法时两个hashCode值不相等,存储的位置不一样,也就没了覆盖,这时候调用set.size()得到2,而不是1,出现错误。
HashMaP get() 源代码:
public V get(Objectkey) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash,table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) ==key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
根据他们的hash 值是否相等,还有内存是否相同,或者是否equals;
然而String,对hashcode进行重写
public int hashCode() {
int h = hash;
if (h == 0) {
int off = offset;
char val[] = value;
int len = count;
for (int i = 0; i < len;i++) {
h =31*h + val[off++];
}
hash = h;
}
return h;
}
String a = new String("adc");
String b = new String("adc");
System.out.println(a.hashCode()==b.hashCode());//true
System.out.println(a==b);//false
总结:可以发现对象不同,hashcode 一样;对象一样hashcode 一样;equals 相同,hashcode相同,equals不同,hashcode 不一定不同也许相同,比如string类中没覆盖equal方法