A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 郭军亮 中级黑马   /  2013-5-16 15:57  /  1880 人查看  /  11 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

请帮忙分析一下String s="abc"和String s=new String("abc")在内存中的情况,为什么前者有一个对象,而后者有两个对象呢

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1

查看全部评分

11 个回复

倒序浏览
用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
String s = "abc"是先在栈中创建一个对String类的对象引用变量str,然后查找栈中有没有存放"abc",
如果没有,则将"abc"存放进栈,并令str指向”abc”,如果已经有”abc” 则直接令str指向“abc”

评分

参与人数 1技术分 +1 收起 理由
袁梦希 + 1

查看全部评分

回复 使用道具 举报
同问,求大神解释
回复 使用道具 举报
本帖最后由 石贤芝 于 2013-5-17 04:05 编辑

第一句代码只有一个对象:“abc”,在字符串常量池中(栈里面),变量 s 不是对象,它是指向对字符串对象“abc”的引用,也就是说 s 的值是对象“abc”的内存地址 。

第二句代码里面有两个对象:对象“abc” 和 对象String("abc"),在堆内存中;
第二句代码执行时,虚拟机先会在堆内存中查找有没有 “abc” 对象,如果没有,就要在堆内存中开辟内存空间创建“abc”对象,然后把“abc”作为参数来创建另外一个对象String("abc")。变量 s 是指向对象String("abc") 的引用。这样第二句代码执行后,堆内存中就多了两个对象。

评分

参与人数 1技术分 +1 收起 理由
Sword + 1

查看全部评分

回复 使用道具 举报
本帖最后由 Super_Class 于 2013-5-17 16:36 编辑

                                 String s1 = "abc";        //创建一个字符串对象在常量池中

                                String s2 = "abc";        这里创建的时候,(没有用new,不会在堆内存中),到常量池中找这个对象。 相当于  s2 = s1;
                                System.out.println(s1.equals(s2)); //true

                                System.out.println(s1==s2);                //true                这里相等时因为常量池中已经有了abc这样一个对象


                                String s3 = new String ("abc");//在堆内存中创建一个字符串对象

                                String s4 = new String ("abc");

                                System.out.println(s2==s3);        //false

                                System.out.println(s3.equals(s4)); //true        String类重写了equals方法


                                 System.out.println(s1==s3);        //false   // 比较的是地址。一个在堆内存,一个在常量池中。肯定不一样

                                System.out.println(s1.equals(s3)); //true  String类重写了equals方法,就变成了比较内容了



评分

参与人数 1技术分 +1 收起 理由
Sword + 1

查看全部评分

回复 使用道具 举报
意思是String s=new String("abc")在常量池中建了一个对象,在堆内存中也建了一个对象,是这个意思吧
回复 使用道具 举报
这个问题问得好啊,面试题,很多人都说不清楚!上面的回答都不完全正确!且看终极答案:
1.String s="abc"
String类在内存中管理着一个文字池(pool of literal strings,也称为字符串常量池,是常量池的一部分),池中所有相同的字符串常量被合并,只占用一个空间。
这里创建“abc”时,先看文字池中有没有abc,没有就创建了一个abc字符串对象。
2.String s1 = new String("abc")
这里先在文字池中创建一个abc对象,同上。然后new String()时,将abc对象复制一份到堆heap中,new一次就复制一个,s1就指向堆中的abc。(参考下面的API文档)
可以用代码验证:
  1. String s1=new String("abc");
  2. String s2=new String("abc");
  3. s1+="d";
  4. System.out.println(s1==s2);//false,说明s1和s2指向的是堆内各自的abc(从文字池中abc复制过来的)
  5. System.out.println(s1);//abcd,说明s1指向abc,不然无法和字符d相连接。
复制代码
参考资料:
JAVA API文档中的解释
public String(String original)
Initializes a newly created String object so that it represents the same sequence of characters as the argument; in other words, the newly created string is a copy of the argument string. Unless an explicit copy of original is needed, use of this constructor is unnecessary since Strings are immutable.
初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本。由于 String 是不可变的,所以无需使用此构造方法,除非需要 original 的显式副本。
网络文章
String s = new String("abc");你真的了解吗???
http://wyz191.iteye.com/blog/139171
String s="abc"及String s=new String("abc")详解
http://www.cnblogs.com/heima-jieqi/archive/2012/04/10/2440086.html

内存图解:

abc.png (65.46 KB, 下载次数: 0)

String s=new String("abc");

String s=new String("abc");

评分

参与人数 1技术分 +1 收起 理由
Sword + 1 赞一个!

查看全部评分

回复 使用道具 举报
Sword 金牌黑马 2013-5-21 09:43:00
8#
如果问题已经解决了,那么大家请把帖子的类型改为“已解决”,谢谢合作
回复 使用道具 举报
ZhaoYuBetter 发表于 2013-5-16 16:06
用new()来新建对象的,它会在存放于堆中。每调用一次就会创建一个新的对象。
String s = "abc"是先在栈中 ...

“abc”是存在栈中的吗?不是存放在常量池中的吗?求解?
回复 使用道具 举报
String("abc") "abc"就是一个对象,后来又new一下就在次穿件乐意对象
回复 使用道具 举报
穿件乐意  改为创建  刚写错了

回复 使用道具 举报
String s = "abc';
先解释一下这个,这个创建对象的时候,是到字符串池中去找“abc”这个对象。(注意,我说“abc”是个对象);
如果找不到,会在字符串池中建一个对象,赋给引用型变量s;

有必要解释一下String s1 = “abc”;   
s == s1;  返回结果 是true;
创建s1的时候,也是先到字符串池中找“abc”对象,如果找到了,就直接把这个对象赋给引用型变量s1;
所以 s和s1是相等的;


String s = new String("abc");
new 对象,都是在堆内存中创建,然后构造方法进栈。接着将引用赋给了 变量s,构造方法弹栈;
每一次new ,都会在堆内存中创建一片空间。所以即使是一样的内容,也不相等
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马