黑马程序员技术交流社区

标题: 这个是前几天天做过的一道题,现在看看好像有问题。 [打印本页]

作者: 简★零度    时间: 2013-11-13 13:04
标题: 这个是前几天天做过的一道题,现在看看好像有问题。
本帖最后由 简★零度 于 2013-11-13 15:15 编辑

public class StringTest
{
        public static void main(String[] args) {            
                String s1 = "a";            
                String s2 = s1 + "b";           
                String s3 = "a" + "b";               
                System.out.println(s2 == "ab");               
                System.out.println(s3 == "ab");              
                System.out.println(s2.equals(s3));               
                System.out.println(s2 == s3);   

        }
}
---------- 运行java程序 ----------
false
true
true
false

输出完成 (耗时 0 秒) - 正常终止
我清楚的知道,s2 s3 的字符串字面值都是"ab",通过 == 其实想比较的是它们是否指向同一对象。
s2.equals(s3)---->比较字符串内容,返回true 没问题
s2 == s3 ---->比较它们是否为同一对象,返回false。
在这个里,+ += 这两个操作符被String唯一重载了。(java是不允许程序员重载操作符的)
s3= "a" + "b"; 这一句实际是调用StringBuilder的append方法将两个字符串连接的。s3最后和 "ab"  == 比较表明指向同一对象
s2= s1 + "b"; 这一句完成后 s2 字符串内容也是"ab",同样是用StringBuilder连接。 s2 最后 和 "ab" == 比较表明不是同一对象
我的疑问就是:在使用 + 操作符操作字符串时,是否参与的只有字符串常量时才不会新建空间产生对象(对应s3这种情况)
  s2 = s1 + "b" 中有引用变量 s1,这是否是导致 s2 == s3 --->false 的原因了??
希望大家能帮下忙
String s1 = "abc"; ---> 内存中一个对象
   String s2 = new String("abc"); --->内存中两个对象
为什么?



作者: 小痞痞    时间: 2013-11-13 13:23
  1. String s1 = "a";     //这个在常量池中
  2.            
  3. String s2 = s1 + "b";

  4. 这句话相当于Stringbuffer sb = new Stringbuffer
  5. sb.append(s1);
  6. sb.append(b);
  7. String s2 = sb.toString();    //返回一个堆内存的引用字符串

  8. String s3 = "a" + "b";        //jvm机制会默认认为String s3 = “ab”   这个还是在常量池中      

  9. System.out.println(s2 == "ab");                //false
  10. System.out.println(s3 == "ab");                //true
  11. System.out.println(s2.equals(s3));            //true
  12. System.out.println(s2 == s3);                   //false
复制代码

作者: pireteMrZ    时间: 2013-11-13 14:38
String类型的字符串是不能改变长度的。程序运行过程中如果涉及到改变长度是通过开辟新的空间实现的。所以通过+连接在一起,实际上是两个空间里的字符。 String s2 = s1 + "b";   实际上是s1的空间后面跟上装有b的空间。而  String s3 = "a" + "b";   是程序为s3开辟了一个空间,将ab放进去。
                 
作者: 迪兰奇迹    时间: 2013-11-13 14:44
String s3 = "a" + "b";  实际上这一步在javac进行编译时会自动变成String s3 = "ab",所以他是在字符串缓冲池中。
而s2= s1 + "b"; 这一句是用StringBuilder的append方法连接后再调用toString( )生成的在缓冲池外的字符串,所以 s2 == s3 --->false.
作者: e‘g_elska_t    时间: 2013-11-13 14:47
因为s2引用了s1这个对象在内存中的地址,s3是把两个字符串相连接后在把地址指向了s3 ,==是判断地址是否相同,equals是判断内容是否相同。
因为对象都是存在在堆内存中,因为newString会在推内存中创建一个String类型的对象,"abc"在内存中也是一个对象
作者: 王雨神    时间: 2013-11-13 15:00
呵呵学到了新知识
作者: 赵晓海    时间: 2013-11-13 15:42
本帖最后由 赵晓海 于 2013-11-13 15:44 编辑

第一问的内存关系图


String s2 = s1 + "b"
等价于
Stringbuffer sb = new Stringbuffer
sb.append(s1);
sb.append("b");
String s2 = sb.toString();

此时先将"a","b"先后添加到StringBurrfer的末端。
然后将引用地址传给s2

s3的赋值与s1的赋值方式相同。我想能弄清楚了吧?

这是第二问的内存关系图:

如图所示,在使用构造方法赋值的时候,String("abc")里面的字符串"abc"是一个匿名对象,需要一块堆内存。而一旦有关键字new,就要开辟一块新空间,这块空间的内容也是"abc"。而这句话执行完成之后,s2指向的是new开辟的空间。所以会有两个对象,但是匿名对象"abc"因为没有被指向,所以属于垃圾,等待被回收。

作者: FFF    时间: 2013-11-13 16:02
赵晓海 发表于 2013-11-13 15:42
第一问的内存关系图

很有心、+10086
作者: 赵晓海    时间: 2013-11-13 16:05
FFF 发表于 2013-11-13 16:02
很有心、+10086

为啥不是95588:P
作者: 狼王    时间: 2013-11-14 07:47
为了黑马,为了美好的未来,加油哈,兄弟




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2