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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 冯建鹏 黑马帝   /  2012-2-13 10:40  /  2910 人查看  /  12 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

String a,b,c;
a="a";
b="b";
c="c";
StringBuffer d = new StringBuffer("abc");
d.append("efg");
总共创建了几个对象?

评分

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

查看全部评分

12 个回复

倒序浏览
String a,b,c; //在栈区创建三个引用类型变量
a="a";    //在堆创建一个对象(由a指向) 该对象值为静态区的"a"常量
StringBuffer d = new StringBuffer("abc");
// 在栈中创建d引用,指向堆中一个新建的StringBuffer类对象,该对象由"abc"进行初始化

这个画下图会好些,但我怕画错,期待楼下高手  - - - -
回复 使用道具 举报
本帖最后由 曾辉 于 2012-2-13 15:47 编辑

8个吧
"a","b","c"本来就是3个对象!
String每次赋值都是重新new一个对象
a="a";所以这里一共两个
StringBuffer d = new StringBuffer("abc");创建两个
对象d(也就是最开始的abc字符串)和引用d
而后面的d.append("efg");都没有生成新的对象 ,StringBuffer 是字符串变量  ,一直是对原串进行操作

评分

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

查看全部评分

回复 使用道具 举报
我想说一共创建了6个对象。
首先String a,b,c;只是声明了a,b,c三个引用,并没有创建对象。
而a="a";b="b";c="c";是把字符串池中(pool)的"a","b","c"三个对象传给三个引用。--->3个对象。
StringBuffer d = new StringBuffer("abc");字符串池中已经存在一个对象"abc",通过new把池中的"abc"对象复制一份,传给引用d。------>2个对象。
d.append("efg");字符串池中创建一个"efg"对象,添加到d中。----->1个对象。
所以我认为一共创建了6个对象。

评分

参与人数 1技术分 +2 收起 理由
唐秀启 + 2 我比较赞同是6个呵呵

查看全部评分

回复 使用道具 举报
关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:

(1)先定义一个名为str的对String类的对象引用变量:String str;

(2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。

(3)将str指向对象o的地址。

值得注意的是,一般String类中字符串值都是直接存值的。但像String str = "abc";这种场合下,其字符串值却是保存了一个指向存在栈中数据的引用!

为了更好地说明这个问题,我们可以通过以下的几个代码进行验证。
复制内容到剪贴板代码:
String str1 = "abc";
String str2 = "abc";
System.out.println(str1==str2); //true
注意,我们这里并不用str1.equals(str2);的方式,因为这将比较两个字符串的值是否相等。==号,根据JDK的说明,只有在两个引用都指向了同一个对象时才返回真值。而我们在这里要看的是,str1与str2是否都指向了同一个对象。
结果说明,JVM创建了两个引用str1和str2,但只创建了一个对象,而且两个引用都指向了这个对象。

我们再来更进一步,将以上代码改成:
复制内容到剪贴板代码:
String str1 = "abc";
String str2 = "abc";
str1 = "bcd";
System.out.println(str1 + "," + str2); //bcd, abc
System.out.println(str1==str2); //false
这就是说,赋值的变化导致了类对象引用的变化,str1指向了另外一个新对象!而str2仍旧指向原来的对象。上例中,当我们将str1的值改为"bcd"时,JVM发现在栈中没有存放该值的地址,便开辟了这个地址,并创建了一个新的对象,其字符串的值指向这个地址。

事实上,String类被设计成为不可改变(immutable)的类。如果你要改变其值,可以,但JVM在运行时根据新值悄悄创建了一个新对象,然后将这个对象的地址返回给原来类的引用。这个创建过程虽说是完全自动进行的,但它毕竟占用了更多的时间。在对时间要求比较敏感的环境中,会带有一定的不良影响。

再修改原来代码:
复制内容到剪贴板代码:
String str1 = "abc";
String str2 = "abc";

str1 = "bcd";

String str3 = str1;
System.out.println(str3); //bcd

String str4 = "bcd";
System.out.println(str1 == str4); //true
str3这个对象的引用直接指向str1所指向的对象(注意,str3并没有创建新对象)。当str1改完其值后,再创建一个String的引用str4,并指向因str1修改值而创建的新的对象。可以发现,这回str4也没有创建新的对象,从而再次实现栈中数据的共享。

我们再接着看以下的代码。
复制内容到剪贴板代码:
String str1 = new String("abc");
String str2 = "abc";
System.out.println(str1==str2); //false 创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

String str1 = "abc";
String str2 = new String("abc");
System.out.println(str1==str2); //false
创建了两个引用。创建了两个对象。两个引用分别指向不同的两个对象。

以上两段代码说明,只要是用new()来新建对象的,都会在堆中创建,而且其字符串是单独存值的,即使与栈中的数据相同,也不会与栈中的数据共享。

评分

参与人数 1技术分 +1 收起 理由
唐秀启 + 1 兄弟别答非所问啊

查看全部评分

回复 使用道具 举报
我怎么觉得是创建了5个对象啊。a="a";b="b";c="c";这里三个。StringBuffer d = new StringBuffer("abc");这里两个(d."abc")。求正解。

评分

参与人数 1技术分 +1 收起 理由
唐秀启 + 1 参与分

查看全部评分

回复 使用道具 举报
李杨 黑马帝 2012-2-13 19:03:51
7#
maochong 发表于 2012-2-13 17:59
关于String str = "abc"的内部工作。Java内部将此语句转化为以下几个步骤:

(1)先定义一个名为str的对Stri ...

(2)在栈中查找有没有存放值为"abc"的地址,如果没有,则开辟一个存放字面值为"abc"的地址,接着创建一个新的String类的对象o,并将o的字符串值指向这个地址,而且在栈中这个地址旁边记下这个引用的对象o。如果已经有了值为"abc"的地址,则查找对象o,并返回o的地址。


你的意思是说字符串池这个“池”是属于堆栈的空间是吗?为什么不属于寄存器空间呢?
回复 使用道具 举报
毛溯澜 黑马帝 2012-2-13 19:54:47
8#
String a,b,c;
a="a";-------1个“a”
b="b";-------1个“b”
c="c";--------1个“c”
StringBuffer d = new StringBuffer("abc");------2个“abc”和new StringBuffer
d.append("efg");----1个“efg”
总共六个

评分

参与人数 1技术分 +2 收起 理由
唐秀启 + 2 各抒己见各抒己见

查看全部评分

回复 使用道具 举报
李杨 黑马帝 2012-2-13 20:11:40
9#
本帖最后由 李杨 于 2012-2-13 20:39 编辑

a,b,c三个引用,引用来自字符串池的三个对象。

new StringBuffer是一个对象,注意!
StringBuffer容器是可变长度的默认长度是16,会随着你加入的数据即append而变化长度。每次加入的字符串都会在到字符串池中找,找不到就创建并且返回给容器加入,由此可以判断new StringBuffer是一个对象,在堆的区域内是可以变化的。那么初始化的数据和append的数据都加入了容器,即缓冲区,而容器的空间是在堆中开辟的,所以缓冲区中的的数据也会存放于堆中。

,另加提问?为什么new会在堆中创建对象,因为当new的时候是动态创建的对象,也就是动态分配的堆内存空间,要动态的分配对象的空间要在堆中进行。

,再次强调原因是StringBuffer是在堆中创建的,会根据你加入的数据变化自己的长度。不是加入就要变化长度,是加入到一定长度的时候才自动变化自己的长度,也不会加入到最后在变化自己的长度。

所以最后是创建6个对象。

评分

参与人数 1技术分 +2 收起 理由
唐秀启 + 2 晕晕乎乎迷迷糊糊,找资料也不知在哪可查到.

查看全部评分

回复 使用道具 举报
a="a";------一个
b="b";-----一个
c="c";------一个
StringBuffer d = new StringBuffer("abc");---------new StringBuffer------一个,“abc”-------一个
d.append("efg");--------一个
六个吧
回复 使用道具 举报
李杨 黑马帝 2012-2-15 17:36:33
11#
本帖最后由 李杨 于 2012-2-15 17:39 编辑
钟保罗 发表于 2012-2-15 16:57
a="a";------一个
b="b";-----一个
c="c";------一个


六个吧?到底几个?

同学:
        这个你需要注意new对象的时候在堆内存中开辟空间,所以呢是一个对象。但是同时初始化一个字符串,这个字符串来自字符串池。初始化的时候在字符串池中找,找不到创建并返回,append加入字符串也是先到字符串池中找,找不到创建返回。所以最后是三个对象。

加上你上面的直接去字符串池中创建的"a", "b", "c" 就是六个。

同学回答的时候别虚心,大胆的说,大胆的错。这样才会让你错的深刻,从而改正错误更为深刻。

加油!!!
回复 使用道具 举报
String a,b,c; //字符串引用,但没有创建对象
a="a";//""表示创建了一个字符串对象,所以"a"表示创建了第一个对象,
b="b";//"b"便是创建第二个对象
c="c";//"c"便是创建第三个对象
StringBuffer d = new StringBuffer("abc");//new 表示创建新对象,第四个;"abc"创建第五个对象
d.append("efg");//"efg",创建第六个对象

评分

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

查看全部评分

回复 使用道具 举报
如上面六个
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马