赞
踩
String这个使用频率极高的数据类型,每个人都能说出很多关于它的使用情景。因为String相对于int等基本类型的内在差别,也常被面试官拿来拿捏面试者。不过确实,虽然我们每天声明无数次String对象,但是对于它的那些事,还是既熟悉又陌生,有点最熟悉的陌生人的感觉。所以今天汇总一下String的常见问题,诸如比较不同形式创建方法创建的对象、不同方法创建了几个对象等问题,结合字节码、源码及分析工具来具体看一下。
先了解一下两个比较方式要比较的内容是什么。
“==”,这个执行的是if_acmpne指令,比较的是栈顶两个引用类型的值。
“equals”,这个内部会先判断“==”的结果,如果是false,继而判断值是否相等,String内部有个value的char数组,保存着字符的序列。
- 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;
- //循环比较每个char的值是否相等
- while (n-- != 0) {
- if (v1[i] != v2[i])
- return false;
- i++;
- }
- return true;
- }
- }
- return false;
- }
- String s1 = "abc";
- String s2 = "abc";
-
- s1 == s2 is true
- s1 equals s2 is true
两个String变量,直接被“=”号赋值成相同的值。“abc”在常量区,s1和s2都指向了同一个常量区的引用。我们看看字节码。
看第5和第11行,执行了ldc(从常量池中取出常量)命令 ,可以看出两个变量都是指向的的同一个常量,所以不管比较的是引用地址还是值,都是相等的。假如我们使用VisualVM查看一下对象的情况,也是一样的结果。
- String s1 = "abc";
- String s2 = new String("abc");
-
- s1 == s2 is false
- s1 equals s2 is true
这里用到了String的new方法。new方法会在堆中创建对象,所以s2会指向在堆中分配的地址,s1仍然指向的常量,所以“==”就不再相等了,而equals比较的是值,所以依然相等。new方法已经不被推荐使用了,因为String是不可变的。看源码。
- /**
- * 它是参数的一个副本. 这个构造函数已经不是必要的了,因为String是不可变的.
- *它内部的value依然和参数对象的value的地址是一样的
- */
- public String(String original) {
- this.value = original.value;
- this.hash = original.hash;
- }
通过VisaulVM查看结果如下:
看到两个变量的地址已经不一样了。但是他们内部的value还是同一个对象。也就是equals依然相等。
- String s1 = new String("abc");
- String s2 = new String("abc");
-
- s1 == s2 is false
- s1 equals s2 is true
有了第二种情况的理解,这个就好理解了,两个new,在堆上分配了两个对象,所以“==”不相等。equals比较的值依然相等。
- String s1 = "a"+"b"+"c";
- String s2 = "abc";
-
- s1 == s2 is true
- s1 equals s2 is true
对于这个结果,是不是有点疑问,三个字符的拼接怎么会和一个完整的字符结果相等呢?JVM在这里做了个优化,直接把三个拼接的结果和“abc”处理成一个对象了。已经完全和第一种等同了。
- String s1 = "a"+"b"+"c";
- String s2 = new String("abc");
-
- s1 == s2 is false
- s1 equals s2 is true
- String s1 = new String("a")+new String("b")+new String("c");
- String s2 = "abc";
-
- s1 == s2 is false
- s1 equals s2 is true
在这篇文章中《“+”真的可以替代StringBuilder吗》我们提到过,连加会被优化为StringBuilder,所以s1的操作就是在操作StringBuilder,前面提到的几种情况,String内部的value都是指向同一个地址的,那么因为这里用到了StringBuilder,而StringBuilder内部也有一个value,所以s1中的value其实指向的是StringBuilder的的value,因此s1和s2不但两个变量的指向不一样,内部的value指向也不一样。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。