日期:2014-05-20  浏览次数:20745 次

请教string的+的问题 谢谢了
String   hello   =   "Hello ";
String   aa   = "   My   "   +   "   world, "+hello;
String   bb   =   "   My   "   +   "   world, "+hello;
if   (aa==bb)  
      System.out.println( "== ");
if   (aa.equals(bb))  
      System.out.println( "equals ");

——————————

只输出equals  
如果aa和bb都   不   加上hello的话,则输出==和equals.
aa和bb的值打印出来都是一样的,加上一个String就使他们指向不同的内存单元,而直接加上”xxx”则仍然指向同一内存单元。为什么呢?     谢谢各位

------解决方案--------------------
如果不加hello
那么在编译时候
" My " + " world, "就已经被合并为 " My world, "
如果加上hello
那么就要在运行的时候创建StringBuilder,然后append上hello,最后toString成String
最后得到两个不同的对象
-------------------------------------------
" My " + " world, "在编译的时候就已经被合并,并不会等到虚拟机执行的时候再去合并.
不加hello的时候 " My world, "这东西是一个被虚拟机缓存,或者说intern的String对象
而aa,bb不过是这个对象的引用.

加上了hello之后在编译时候无法确定aa和bb的值,必须要到运行时候创建新的String对象.
------解决方案--------------------
首先把问题摆出来,先看这个代码


String a = "ab ";
String b = "a " + "b ";
System.out.println((a == b));



打印结果会是什么?类似这样的问题,有人考过我,我也拿来考过别人(蛮好玩的,大家也可以拿来问人玩),一般答案会是以下几种:


1.true

"a " + "b " 的结果就是 "ab ",这样a,b都是 "ab "了,内容一样所以 "相等 ",结果true

一般java新人如是答。

2.false

"a " + "a "会生成新的对象 "aa ",但是这个对象和String a = "ab ";不同,(a == b)是比较对象引用,因此不相等,结果false

对java的String有一定了解的通常这样回答。

3.true

String a = "ab ";创建了新的对象 "ab "; 再执行String b = "a " + "b ";结果b= "ab ",这里没有创建新的对象,而是从JVM字符串常量池中获取之前已经存在的 "ab "对象。因此a,b具有对同一个string对象的引用,两个引用相等,结果true.

能回答出这个答案的,基本已经是高手了,对java中的string机制比较了解。

很遗憾,这个答案,是不够准确的。或者说,根本没有运行时计算b = "a " + "b ";这个操作.实际上运行时只有String b = "ab ";

3的观点适合解释以下情况:


String a = "ab ";
String b = "ab ";
System.out.println((a == b));


如果String b = "a " + "b ";是在运行期执行,则3的观点是无法解释的。运行期的两个string相加,会产生新的对象的。(本文后面对此有解释)


4.true

下面是我的回答:编译优化+ 3的处理方式 = 最后的true

String b = "a " + "b ";编译器将这个 "a " + "b "作为常量表达式,在编译时进行优化,直接取结果 "ab ",这样这个问题退化


String a = "ab ";
String b = "ab ";
System.out.println((a == b));



然后根据3的解释,得到结果true


这里有一个疑问就是String不是基本类型,像

int secondsOfDay = 24 * 60 * 60;

这样的表达式是常量表达式,编译器在编译时直接计算容易理解,而 "a " + "b " 这样的表达式,string是对象不是基本类型,编译器会把它当成常量表达式来优化吗?

下面简单证明我的推断,首先编译这个类:


public class Test {
private String a = "aa ";
}


复制class文件备用,然后修改为


public class Test {
private String a = "a " + "a ";
}


再次编译,用ue之类的文本编辑器打开,察看二进制内容,可以发现,两个class文件完全一致,连一个字节都不差.

ok,真相大白了.根本不存在运行期的处理String b = "a " + "b ";这样的代码的问题,编译时就直接优化掉了。


下面进一步探讨,什么样的string + 表达式会被编译器当成常量表达式?

String b = "a " + "b ";