赞
踩
字符串的“=”操作比较的是左右操作引用指向的地址是否相同。
看以下代码:
String str1 = "hello";
String str2 = "word";
String str3 = "hello";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str2 == str3);
解释:str1和str3指向的都是“hello”对象,而此对象存在于字符串常量池中且只有一份,所以str1和str3这两个引用指向的是同一对象,所以第二个输出是true;第一个和第三个输出是false;
字符串的拼接有两种情况:
此情况下,编译器会在编译期间自动将两个字符串常量合并为一个常量字符串
String str1 = "hel"+"lo";
String str2 = "hello";
System.out.println(str1 == str2);
解释:str1在加载时,会先将“hel”和“lo”进行拼接成“helllo”,然后在字符串常量池中检查,发现没有出现过“hello”,则在字符串常量池中创建一个“hello”对象,其地址赋值给str1,str2在加载时,拿着“hello”在字符串常量池检查发现已经有“hello”字符串对象了,直接将“hello”的地址赋值给str2,所以运行结果为true;
先看一组代码:
String str1 = "hel"; //①
String str2 = str1+"lo"; //②
String str3 = str1+"lo"; //③
String str4 = "hello"; //④
System.out.println(str2 == str3); //⑤
System.out.println(str3 == str4); //⑥
System.out.println(str2 == str4); //⑦
猜猜运行结果是什么?
运行结果如下:
false
false
false
这是为什么呢?
刚学到这时,我也是一头雾水,百思不得其解。
原来在变量参与字符串拼接时会在底层创建一个StringBuilder对象,每次拼接都会被优化为调用一次StringBuilder的append方法。代码在加载第②行时,底层首先会创建一个StringBuilder对象,假设对象名字是stringBuilder,先用此对象append一次str1,即:stringBuilder.append(str1),遇到“+”,然后继续调用append方法去append(“lo”)。遇到“ ;”代表此行执行结束,在调用StringBuilder类的toString()方法将结果赋值给str2。第三行操作逻辑与第二行一致,值得注意的是每次都会创建一个StringBuilder对象,且最后都会调用toString()方法,所以str2和str3都是指向不同引用的对象,自然和str4也是不相等的。
字符串的+=操作和+操作并没有什么区别,只是在创建StringBuilder对象时会先append一次"+="符号的左操作数。
例如:
String a = "hel";
a += "lo";
执行时StringBuilder对象假设是stringBuilder会这样执行:stringBuilder.append(a).append(“lo”)
值得注意的是在循环中尽量不用String的“+”拼接操作,而使用的是StringBuilder对象的append( )方法。
String的构造方法最常用的是传入一个字符串对象进行初始化。
例如:
String str = new String("hello");
那么它底层会怎么运行呢?
首先,采用构造方法new新建一个字符串对象时,JVM首先在字符串常量池中查找有没有“hello”这个对象,发现没有,其首先会在字符串常量池中创建一个“hello”字符串对象,然后再在堆上创建一个“hello”对象,让后将堆中这个“hello”字符串对象的引用赋值给str。而如果有的话,则不在池中再去创建“hello”这个对象了,直接在堆中创建一个“hello”字符串对象,然后将此对象的地址返回给str。
我们可能会遇到下面情形:
String str1 = new String("hel") + new String("lo");
String str2 = "hello";
System.out.println(str1 == str2);
那么在第一行执行时是怎么运行的呢?
按照上面的逻辑来,调用构造方法时,先会检查字符串常量池中是否有“hel”对象,结果没有然后在字符串常量池中创建一个“hel”对象,然后对“lo”也是,在字符串常量池中创建一个“lo”对象,然后拼接,在堆中创建一个“hello”对象,将此对象的地址赋值给str1。
有以下两个作用:
以下面代码为例:
String str = new String("hel")+new String("lo");
str = str.intern();
1.当字符串常量池中不存在“hello”这个字符串的引用时,将这个对象的引用加入常量池中,返回这个对象的引用。(注意:说的是引用即地址,地址都放大了字符串常量池中)
2.当常量池中存在“hello”这个字符串的引用时,直接返回这个对象的引用。
看下面练习:
String str1 = new String("hello").intern();
String str2 = "hello";
运行结果是 true;
解释:第一行在执行时,先new一个String对象,检查字符串常量池中没有“hello”,则在常量池中创建一个“hello”对象,继续执行代码遇到intern( )方法,此时再去常量池中查找发现存在“hello”对象,然后将字符串常量池中的“hello”对象的引用(即地址)返回给str1.。第二行执行时也是直接将字符串常量池中的“hello”引用赋值给str2,所以结果为true;
最后看一下下面的题,看看自己能否全对:
String str1 = new String("abc");
String internStr1 = str1.intern();
String poolStr1 = "abc";
System.out.println(str1 == internStr1);
System.out.println(str1 == poolStr1);
System.out.println(internStr1 == poolStr1);
String str2 = new String("hel")+("lo");
String internStr2 = str2.intern();
String poolStr2 = "hello";
System.out.println(str2 == internStr2);
System.out.println(str2 == poolStr2);
System.out.println(internStr2 == poolStr2);
答案:
false
false
true
true
true
true
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。