equals和 == 的区别解析 + hashCode方法的小见解
==既可以比较基本类型(比较值),也可以比较引用类型(比较引用地址)。
来看看两段equals源码
Object类下的equals方法
public boolean equals(Object obj) {
return (this == obj);
}
String类下的equals函数
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
可以看出如果是Object下的equals方法,如果没有对其进行重写,那么该方法和==的作用是一样的。
String下的equals方法是重写了的,先比较当前对象的地址和要比较的对象的地址是否相等,如果不相等再判断是否为String的实例化对象,然后比较length和value是否相同。
String的equals方法用的比较广泛,故很多人都误以为所有equals都是比较值的方法。
下面来看一个栗子
public static void main(String[] args) {
String s1 = "foo";
String s2 = "foo";
System.out.println("s1 equals s2 :" + s1.equals(s2));
System.out.println("s1 == s2 :" + (s1 == s2));
System.out.println(s1.hashCode() + " " + s2.hashCode());
System.out.println("--------------------------------");
String s3 = new String("ff");
String s4 = new String("ff");
System.out.println("s3 equals s4 :" + s3.equals(s4));
System.out.println("s3 == s4 :" + (s3 == s4));
System.out.println(s3.hashCode() + " " + s4.hashCode());
System.out.println("--------------------------------");
StringBuffer sb1 = new StringBuffer("off");
StringBuffer sb2 = new StringBuffer("off");
System.out.println("sb1 equals sb2 :" + sb1.equals(sb2));
System.out.println("sb1 == sb2 :" + (sb1 == sb2));
System.out.println(sb1.hashCode() + " " + sb2.hashCode());
}
运行结果
s1 equals s2 :true
s1 == s2 :true
101574 101574
--------------------------------
s3 equals s4 :true
s3 == s4 :false
3264 3264
--------------------------------
sb1 equals sb2 :false
sb1 == sb2 :false
460141958 1163157884
原因分析
①
s1 s2 都是直接赋值的,首先s1会在java常量池中寻找foo对象,如果没有,在堆内存中new一个值为“foo”的对象放在常量池中并返回引用,之后s2再用直接赋值的方法时,如果值相同就直接引用这个对象,不用新建。
另外,因为s1和s2都是String类型的,所以equals方法是重写了的。
s1 == s2 比较的是内存地址,因为s1和s2是同一个对象,故内存地址相同。s1.equals(s2) 为true是因为equals方法重写过,先比较字符串的长度,再比较value,故为true。
②
s3 s4 都是new新建的,新建对象是直接在堆内存中新建一个对象再对其进行赋值。也就是说用new创建的对象都不是同一个对象。
解释和①大致一样,因为不是相同对象,所以s3 == s4 为false,内存地址不同。
③
sb1 sb2 是StringBuffer类型(equals没有重写,使用的是Object的)
sb1 == sb2 内存地址不同,为false
sb1.equals(sb2) 由于equals方法没有重写,所以等价于 == ,故也为false。
关于hashCode()方法
以前我一直以为hashCode()可以判断二者是不是同一对象,后来才发现原来不同对象的hashCode也是可以相同的,我们一起来瞅瞅hashCode的源码
* As much as is reasonably practical, the hashCode method defined by
* class {@code Object} does return distinct integers for distinct
* objects. (This is typically implemented by converting the internal
* address of the object into an integer, but this implementation
* technique is not required by the
* Java™ programming language.)
*
* @return a hash code value for this object.
* @see java.lang.Object#equals(java.lang.Object)
* @see java.lang.System#identityHashCode
*/
public native int hashCode();
我们可以看到hashCode是一个native方法,看不到实现,注解中hashCode返回的是由对象存储地址转化得到的值。
String重写的hashCode方法
public int hashCode() {
int h = hash;
if (h == 0 && value.length > 0) {
char val[] = value;
for (int i = 0; i < value.length; i++) {
h = 31 * h + val[i];
}
hash = h;
}
return h;
}
可以看出对于String类型,hashCode是根据value值决定的,只要value值相同,hashCode就相同。
而StringBuffer没有重写hashCode函数,这意味着该对象的每个实例都应该是唯一的hashCode。
这就解释了为什么s3、s4的hashcode相同以及sb1和sb2的hashcode不同。
Java小白的第一篇文章~
如有什么错误,欢迎指正嗷