今天在又碰到俩了,先用代码来说吧:
String s1="java01";
String s4="java01";
System.out.println(s1.hashCode()==s4.hashCode());
System.out.println(s1.equals(s4));
System.out.println(s1==s4);
如果是这样的话,这三个判断都是true,因为String这样创建是在栈中,所以此时s1和s4的值相等,通过API,我发现String的hashCode值的算法只喝String里面的值有关:
String 对象的哈希码根据以下公式计算:
s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
使用 int 算法,这里 s 是字符串的第 i 个字符,n 是字符串的长度,^ 表示求幂。(空字符串的哈希值为 0。)
这说明只要String里面的内容一样,hashcode就一样,而String的equals方法似乎和hashcode无关,源码里面equals方法是这样写的:[code=java]public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}[/code]主要是通过每一个字符的对比来判断是否相等。
java中的基本类型也对equals方法和hashcode方法进行重写了,所以这两个方法没有什么关联。
接着我从Object的源码中找到其equals方法:
public boolean equals(Object obj) {
return (this == obj);
}
也就是说,我们自己定义的类,如果没有重写equals方法,那么其结果和==是一样的。
今天看到hashset的时候,毕老师说,如果他们的hashcode一样,还会继续根据equals方法来判断其是否相同,原来没有重写的equals方法也是根据地址来判断的,难怪即使你把类的hashcode重写成都返回同样的值,hashset还是会判断出是否是同样的对象,因为地址是不能改变的:[code=java]public class HashDemo {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
HashDemo h1=new HashDemo();
HashDemo h2=new HashDemo();
System.out.println(h1.hashCode()==h2.hashCode());
HashSet hs=new HashSet();
hs.add(h1);
hs.add(h2);
Iterator it=hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
}
}
@Override
public int hashCode() {
// TODO Auto-generated method stub
return 110;
}
}[/code]就像这样,即使返回的hashcode一样,但是仍然会add进hashset里面。
所以如果没有重写equals方法,自定义类里面的equals方法和==是一样的,而java中定义好的类大部分是有重写过equals方法的,所以这两个才会有时候出现区别。
不知道我这样分析的对不对,请大家指教。 |