当前位置:   article > 正文

String的比较,你都搞清楚了吗_string 比较

string 比较

String这个使用频率极高的数据类型,每个人都能说出很多关于它的使用情景。因为String相对于int等基本类型的内在差别,也常被面试官拿来拿捏面试者。不过确实,虽然我们每天声明无数次String对象,但是对于它的那些事,还是既熟悉又陌生,有点最熟悉的陌生人的感觉。所以今天汇总一下String的常见问题,诸如比较不同形式创建方法创建的对象、不同方法创建了几个对象等问题,结合字节码、源码及分析工具来具体看一下。

先了解一下两个比较方式要比较的内容是什么。

“==”,这个执行的是if_acmpne指令,比较的是栈顶两个引用类型的值。

“equals”,这个内部会先判断“==”的结果,如果是false,继而判断值是否相等,String内部有个value的char数组,保存着字符的序列。

  1. public boolean equals(Object anObject) {
  2. if (this == anObject) {
  3. return true;
  4. }
  5. if (anObject instanceof String) {
  6. String anotherString = (String)anObject;
  7. int n = value.length;
  8. if (n == anotherString.value.length) {
  9. char v1[] = value;
  10. char v2[] = anotherString.value;
  11. int i = 0;
  12. //循环比较每个char的值是否相等
  13. while (n-- != 0) {
  14. if (v1[i] != v2[i])
  15. return false;
  16. i++;
  17. }
  18. return true;
  19. }
  20. }
  21. return false;
  22. }
  • 第一种
  1. String s1 = "abc";
  2. String s2 = "abc";
  3. s1 == s2 is true
  4. s1 equals s2 is true

两个String变量,直接被“=”号赋值成相同的值。“abc”在常量区,s1和s2都指向了同一个常量区的引用。我们看看字节码。

看第5和第11行,执行了ldc(从常量池中取出常量)命令 ,可以看出两个变量都是指向的的同一个常量,所以不管比较的是引用地址还是值,都是相等的。假如我们使用VisualVM查看一下对象的情况,也是一样的结果。

  • 第二种 
  1. String s1 = "abc";
  2. String s2 = new String("abc");
  3. s1 == s2 is false
  4. s1 equals s2 is true

这里用到了Stringnew方法。new方法会在堆中创建对象,所以s2会指向在堆中分配的地址,s1仍然指向的常量,所以“==”就不再相等了,而equals比较的是值,所以依然相等。new方法已经不被推荐使用了,因为String是不可变的。看源码。

  1. /**
  2. * 它是参数的一个副本. 这个构造函数已经不是必要的了,因为String是不可变的.
  3. *它内部的value依然和参数对象的value的地址是一样的
  4. */
  5. public String(String original) {
  6. this.value = original.value;
  7. this.hash = original.hash;
  8. }

通过VisaulVM查看结果如下:

 看到两个变量的地址已经不一样了。但是他们内部的value还是同一个对象。也就是equals依然相等。

  • 第三种
  1. String s1 = new String("abc");
  2. String s2 = new String("abc");
  3. s1 == s2 is false
  4. s1 equals s2 is true

有了第二种情况的理解,这个就好理解了,两个new,在堆上分配了两个对象,所以“==”不相等。equals比较的值依然相等。

 

  • 第四种
  1. String s1 = "a"+"b"+"c";
  2. String s2 = "abc";
  3. s1 == s2 is true
  4. s1 equals s2 is true

对于这个结果,是不是有点疑问,三个字符的拼接怎么会和一个完整的字符结果相等呢?JVM在这里做了个优化,直接把三个拼接的结果和“abc”处理成一个对象了。已经完全和第一种等同了。 

  •  第五种,知道了第四种情况中JVM的优化,那么这种和第二种的分析就是一样的了,可参照着理解。
  1. String s1 = "a"+"b"+"c";
  2. String s2 = new String("abc");
  3. s1 == s2 is false
  4. s1 equals s2 is true
  • 第六种
  1. String s1 = new String("a")+new String("b")+new String("c");
  2. String s2 = "abc";
  3. s1 == s2 is false
  4. s1 equals s2 is true

在这篇文章中《“+”真的可以替代StringBuilder吗》我们提到过,连加会被优化为StringBuilder,所以s1的操作就是在操作StringBuilder,前面提到的几种情况,String内部的value都是指向同一个地址的,那么因为这里用到了StringBuilder,而StringBuilder内部也有一个value,所以s1中的value其实指向的是StringBuilder的的value,因此s1s2不但两个变量的指向不一样,内部的value指向也不一样。

 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/594306
推荐阅读
相关标签
  

闽ICP备14008679号