java中比较String是否相同为何用equals而不是==?

参考自:
https://www.cnblogs.com/baotong-9396/p/7182906.html
http://www.cnblogs.com/panxuejun/p/5866869.html

如题

      作为一个写惯了js的人来说,初次接触java会有各种不习惯。其中有一个比较显著地不能理解的现象就是在java中比较两个String值是否相等居然用equals()而不是==。貌似在js中,比较值相等一个==就解决了,多么舒服。为什么java不行呢?
      首先,写过js的都知道,js支持=,==以及===三种等号,第一个代表赋值,第二个用来表示值是否相等,而第三个用来判断是否是完全相等的对象。但是!java里并没有===比较符

      在js中,===可以判断两个对象是否完全相等,不仅比较值也比较了内存地址,类型等,而java中的==其实和js中的===一样。这种比较是针对两个String类型的变量的引用,也就是说如果两个String类型的变量,它们所引用同一个String对象(即指向同一块内存堆),则==比较的结果是true
      而当两个String对象通过equals()方法来进行比较时,其实就是对String对象所封装的字符串内容进行比较,也就是说如果两个String对象所封装的字符串内容相同(包括大小写相同),则equals()方法将返回true。(String对象继承自Object,并且对equals()方法进行了重写。)

示例一:

1
2
3
4
String s1 = new String("Hello");
String s2 = new String("Hello");
System.out.println(s1 == s2); // false
System.out.println(s1.equals(s2)); // true

示例二:

1
2
3
4
String s1 = "Hello";
String s2 = "Hello";
System.out.println(s1 == s2); // true
System.out.println(s1.equals(s2)); // true

      为啥示例一和示例二打印输出不一样呢?
      很简单的,示例一通过new关键字在内存里开辟了两处空间,使用==比较当然是false了。而示例二直接将String作为基本类型使用,因此虚拟机不会为它们分配新的内存空间,而是到String缓冲池中来寻找。

示例三:

1
2
3
4
String s1 = new String("Hello");
String s2 = s1;
System.out.println(s1 == s2); // true
System.out.println(s1.equals(s2)); // true

      这个也很好理解,将s1赋值给s2,其实就是让s2s1引用同一个对象。

      在见识了以上三种应用示例后,我们是不是有必要去看看equals()方法的源码实现,以方便我们更好的理解?
String.class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
private final char value[];
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
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;
}

  1. 以示例一为例,通过new关键字分别调用了public String(String original)构造函数,通过该构造函数对valuehash进行赋值。
  2. 随后先判断s1,s2是不是引用同一个对象,是的话返回true不是继续下一步。
  3. 通过判断用来比较的第二个对象是不是String类型,之后通过强转进一步确保。
  4. 用一个变量n来保存第一个String对象值的长度,然后先比较这两个String对象值长度是否相等,相等继续否则返回false
  5. 将这两个String对象的值分别保存进两个char类型的数组,通过循环对比相同下标对应的字符是否相等,存在一个不等就结束并返回false,如果全部都一一对应相等,那么就返回true

对equals做个总结

      以上主要对equals()的源码进行了分析,仔细观察跟compareTo()里面的源码很大程度上相似,感兴趣的可以去看看哦。

延伸

      String.class里面的equals()重写覆盖自顶级对象Object,Object里面的equals()源码很简单,直接用==判断两个对象是不是相同。

      如果两个Object类型的对象使用equals()并返回true,说明它们是相同的,包括在内存中的存储地址,所以它们的hashcode也相同!!!

      思考一下:如果两个非Object类型的对象(例如本文中的String)使用equals()并返回true,那么它们的hashcode是否相同呢?
示例四:

1
2
3
4
5
6
7
8
String s1 = new String("Hello");
String s2 = new String("Hello");
String s3 = "Hello";
System.out.println(s1.equals(s2)); // true
System.out.println(s1 == s2); // false
System.out.println(s1.hashCode()); // 69609650
System.out.println(s2.hashCode()); // 69609650
System.out.println(s3.hashCode()); // 69609650

      通过上述示例可以看到,s1s2其实是对两个不同的对象的引用,它们仅仅是值相同罢了,但是它们却拥有着相同的hashcode!!!

      那么,是不是equals相同hashcode一定相同呢?
      先给出结论:

  1. 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。
  2. 如果x.equals(y)返回“false”,那么x和y的hashCode()有可能相等,也有可能不等。

      为什么会做出上面的判断呢?不妨看看源码实现吧。依然以String.class为例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
private int hash; // Default to 0
public String(String original) {
this.value = original.value;
this.hash = original.hash;
}
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;
}

研读源码思考:

      主要关注hashCode()内部实现,我们发现它最终返回的是h,而h其实就是通过value值循环遍历累加得到的。那么如果两个对象调用equals相等,不就意味着它们的值相等吗?hashCode()也是通过值来计算的,这样能不等吗?

      那么为什么说hashcode相等,对象未必相同呢?
      我个人理解,虽然hashCode()依赖于value值,但是它并没有逐一去比较每个下标对应的值是否相同,仅仅是判断累加值,那么假设两个对象的value值不同但是累加值却相同不就造成了hashcode相同吗?可事实上这两对象并不相同!

Newer Post

管中窥豹:HashMap原理学习以及jdk1.8版本中源码的变更

学习自https://mp.weixin.qq.com/s/1bmNx-gw5-2jucn6i8XfZwhttps://www.cnblogs.com/skywang12345/p/3310835.htmlhttps://blog.csdn.net/unscdf117/article/details …

继续阅读
Older Post

Java main方法

参考自:https://blog.csdn.net/show_me_the_world/article/details/47106191https://blog.csdn.net/show_me_the_world/article/details/47106191 背景&nbsp;&nbsp;&nb …

继续阅读