黑马程序员 另一道内存分配的面试题

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

另一道题是这样的:

String str = new String (“Practical ”) ; str += “Java” ;共产生几个对象?

估计大家都很熟悉这道题,我查阅资料的时候发现很早之前就有很多人讨论这个问题。我看毕老师视频的时候,他也提到过一次,如果这样定义String str = new String (“abc ”) ;,那会创建两个对象,如果这样创建String str = new String () ;只会创建一个。当时,我并不明白是为什么,今天百度了2个多小时,越发的觉得这个问题问的好无聊,我管他几个呢,只要知道他最后指向的对象不就行了嘛,但是毕竟想了这么久,又看了网上那么多争议的答案,我也来表个态,证明一下毕老师的观点。

网上关于这个问题的答案有2个、4个和5个的,我找到的最奇葩的答案是5个的,摘录如下:

按照运算的优先顺序,=赋值运算符是最后,而按从左向右的顺序
1. String str 定义对象如果不分配初值,系统会分配一个""的初始值.这个运算符的意思是首先在栈中创建一个String 的引用名为str 然后在堆中创建空字符串,将这个字符串的首地址给str这个引用.
这时就创建了第一个对象.
2. new String("Practical ") 这个操作符为创建一个匿名引用,new本身是在堆中开辟一段内存空间。然后把这个空间的首地址给了一个匿名引用.这是第二个对象.
3. 由于java里有字String对象是不可改变对象。所以当内容发生改变时,是新开内存而非在原有的基础上修改,这里注意StringBuilder是可改变对象是非编程安全的,所以在new String的对象通过赋值操作符=号把值赋给str这个引用的时候,由于是两个不同内容的str所以就会产生第三个对象,而原有的两个对象虽然没有了引用,但它们还是在内存中存在。只是str现在所表示的内存的值为“Practical”.这就是产生的第三个对象
4.使用 str += "Java"; 这句话是这样,实际这是 str = str + "java";
按运算优先顺序而言,首先是 + 这样的算术运算,然后才是=的赋值运算. 这里的"java"是个实际是产生了一个匿名对象相当于new String("java") 这里就是第四个对象。
5.传说中的第五个对象,而由于str是String类的的实例。str通过+操作符所字符串连接,这时就会产生所谓的第五个对象,因为str是线程安全所以内容发生变化,会新开空间用来存储,这时就有了第五个对象!

与此题相似的还有一道题:String str=new String()+"abc"一共创建了几个对象? 当然这个题也有相似的奇葩答案:

String str=new String()+"abc"
一共创建4个字符串:
1."abc"为一个字符串
2.new String()创建了一个字符串
3.new String+"abc"创建了一个字符串(String类型连接是新建一个新的字符串,不同于StringBuffer)
4.str为指向新生成的字符串的引用,本身会在内存中创建一个String类型的引用对象

为什么说这两个奇葩答案相似的,因为他们都提到了一个引用对象,就是String str这个操作,都被认为会在内存中创建对象。所以他们的答案不是少算了而会多算了,这让初学java的人肯定一头雾水,怀疑自己的学习水平。我们在学习面向对象的时候都被老师告知过,只有在初始化,或new对象的时候,这个对象才会被创建,仅仅是定义引用不算是创建对象,要不你定义一个null引用,你调用谁去?

所以但凡数上str是对象的答案或解释,不用看,一律是错的。另外还有数上StringBuffer的,我觉得要再数上它,可得多加上好几个了。

我百度到的有两个比较靠谱的帖子:http://duzhizj.blog.163.com/blog/static/34324890201291805834778/  

还有这个:http://blog.csdn.net/yuanyuanmmm/article/details/4922587。这个说的有点相似,但是我觉得还有的地方说的不妥,要比较完整、比较正确的解释这个问题,还得再加上这篇帖子:http://developer.51cto.com/art/201009/225071_2.htm ,这样就差不多啦。

下面做一个小总结:他们都提到把String str = new String (“abc ”) ;分成4部分来看,只有后面两个有创建对象的可能,new就不用说了,肯定算一个,但是new里面包不包含“abc”对象,“abc”仅仅作为初始化存在么?它们算一个,还是算两个?当时我少数了就是因为没有把“abc”看做是一个对象,但是它是的,是一个匿名对象。所以String str = new String (“abc ”) ;这句话创建了2个对象。就像String str = “abc ” ;是一个对象一样,作为对象的是”abc“,而不是str。

他们还都提到了字符串池,不过应该叫常量池,而且他们关于存贮的解释也不正确。举个例子:String a="ab"+"cd";这个在帖子中说建立了三个对象,不会的,只有一个,编译器自动优化了,所以"ab"+"cd"就直接是按"abcd"保存的。两篇帖子的最后问题都是一样的,都落脚在String str = “abc ” ;这个对象生成的问题上。

那我就来纠正一下,他们剩下的问题。首先new和直接赋值,对象生成的时间就不一样,new是运行时创建对象,数据存放在堆内,直接赋值是在编译时创建对象,数据存放在常量池,在方法区内,可以共享,而且还存在编译时期的优化操作。就算一个字符串已经创建,在常量池中,你new一下,照样会在堆内产生一个对象,而很多人都认为那个字符串是可以共享的,这是不对的。只有在编译时期才存在共享的情况,为了节约内存而已。

好了,公布一下答案吧,第一个是4个,第二个是3个。String str = new String (“abc ”) ;这种形式是创建2个对象,String str =new String ()  ;这种是创建一个对象,不过没啥意义,因为字符串不能改变,加一个字符串后,还得需要创建新的对象,浪费内存。

---------------------- <a href="http://edu.csdn.net"target="blank">ASP.Net+Android+IO开发S</a>、<a href="http://edu.csdn.net"target="blank">.Net培训</a>、期待与您交流! ----------------------

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值