黑马程序员技术交流社区

标题: 关于创建的对象的个数? [打印本页]

作者: 徐宏伟    时间: 2012-9-5 19:33
标题: 关于创建的对象的个数?
在学习的时候,只要是涉及到new,就会创建一个对象;

例如: String  str = new String(“lll”);//这样就创建一个string类型的对象;每new一次,string类型的对象就增加一个;

那么 string str1 = “123”; string str2 = ”123“;  string str3 = ”123“;  //请问这样的话是创建了几个对象?(备注:字符串都是”123“是一样的)


作者: 王海舟    时间: 2012-9-5 21:04
本帖最后由 王海舟 于 2012-9-6 23:20 编辑

更正之后的答案:
共创建了1个对象。

讲解如下:
string str1 = "123" 这一句代码到底做了什么呢?

它首先创建了一个string类型的对象(或者叫做实例),这个对象被存储在托管堆中,它的值是"123",然后将这个对象的引用(也就是地址或者叫指针)赋值给str1变量,而str1这个变量的值是保存在堆栈中的。

但是,string类型不同于一般的引用类型,在创建string str2="123"的时候,它会先去托管堆中寻找是否存在"123",如果存在,它会将托管堆中"123"这个对象的地址赋值给str2变量,创建str3的时候同理。

所以string str1 = "123"、string str2="123"string str3="123"
共在托管堆中开辟了一块内存空间,创建了一个对象。
共在堆栈中开辟了三块内存空间,创建了三个变量,变量保存的值是对象"123"的地址。








作者: 廖创发    时间: 2012-9-5 21:55
创建了3个对象。因为每次实例化的时候都会在堆栈中分配一个空间储存,所以虽然字符串一样,但str1,str2,str3不重叠。
作者: 徐宏伟    时间: 2012-9-6 10:02
王海舟 发表于 2012-9-5 21:04
先直接给出答案:
共创建了3个对象。

谢谢!!!
作者: 徐宏伟    时间: 2012-9-6 10:02
廖创发 发表于 2012-9-5 21:55
创建了3个对象。因为每次实例化的时候都会在堆栈中分配一个空间储存,所以虽然字符串一样,但str1,str2,s ...

谢谢!!!
作者: 阿磊-_-    时间: 2012-9-6 20:56
不对吧 。。字符串如果相同,变量名都指向同一个对象。应该只有一个对象! 如果你特意new 一个的话是又一个对象  !  大家认为呢?
作者: 徐宏伟    时间: 2012-9-6 21:09
阿磊-_- 发表于 2012-9-6 20:57
不对吧 。。字符串如果相同,变量名都指向同一个对象。应该只有一个对象! 如果你特意new 一个的话是又一个 ...

我觉得net该有这么一个优化……new的时候会增加,但是直接那么赋值的话,觉得该是一个,但是没有理论依据…………目前还没找到这方面的说明。

//======前提:都是同一个字符串;
作者: 徐宏伟    时间: 2012-9-6 21:11
王海舟 发表于 2012-9-5 21:04
先直接给出答案:
共创建了3个对象。

哥们,关于 "托管堆"  和 “堆栈” 的区别,或者说有木有相关的资料,推荐下哈~~~谢了先
作者: 杨千里    时间: 2012-9-6 21:11
String  str = new String(“lll”);//创建2个对象


string str1 = “123”;
string str2 = ”123“;
string str3 = ”123“;
创建3个对象,三个对象指向同一个引用,
可以理解为,三个人共用一台电脑  
作者: 王海舟    时间: 2012-9-6 23:19
本帖最后由 王海舟 于 2012-9-6 23:35 编辑
阿磊-_- 发表于 2012-9-6 20:56
不对吧 。。字符串如果相同,变量名都指向同一个对象。应该只有一个对象! 如果你特意new 一个的话是又一个 ...

非常感谢你的回复,看来string类型比我理解的更为特殊一些,不仅是不可变类型,在直接赋值的时候都会和普通引用类型变量有所区别。

这里再补充一点string类型另一个不同于普通引用类型的特点:就是它的不可变性
举例说明:
            string str1 = "123";
            string str2 = str1;
            Console.WriteLine("str1={0},str2={1}",str1,str2);  //输出str1=123,str2=123
            str1 = "456";
            Console.WriteLine("str1={0},str2={1}", str1, str2);//输出str1=456,str2=123

如果按照普通引用类型的理解,str1和str2变量的中存储的值是相同的,都是托管堆中对象"123"的地址,那么str1的值改变之后,也就是托管堆中对象的值改变了,str2的值也应该改变,可是结果却不是这样,这就是string类型的特殊。
实际情况是,str1被再次赋值为"456"的时候,并没有改变托管堆中原有对象"123"的值,而是重新开辟了一块内存空间来存储一个新的对象"456"这个值。所以赋值过后的str1和str2中存储的值已经不同了,它们指向了两块不同的托管堆中的内存空间。

作者: 王海舟    时间: 2012-9-6 23:39
徐宏伟 发表于 2012-9-6 21:11
哥们,关于 "托管堆"  和 “堆栈” 的区别,或者说有木有相关的资料,推荐下哈~~~谢了先 ...

我大学的时候学得比较杂,都是自己东拼西凑的理解,没有系统的学习过,没什么系统的资料推荐呢。。。抱歉了
作者: 黑马杨凯    时间: 2012-9-7 08:41
本帖最后由 黑马杨凯 于 2012-9-7 09:11 编辑

            string str1 = "aaa";
            string str2 = "aaa";
            //new一个,真正的在堆上新开一块空间存放"aaa"
            string str3 = new string(new char[3] { 'a', 'a', 'a' });
            
            //判断是否指向同一个对象
            Console.WriteLine("str1:{0}、str2:{1}指向同一个对象:{2}",str1,str2, string.ReferenceEquals(str1, str2));//true
            Console.WriteLine("str1:{0}、str3:{1}指向同一个对象:{2}",str1,str3, string.ReferenceEquals(str1, str3));//false
            Console.WriteLine("str2:{0}、str3:{1}指向同一个对象:{2}",str2,str3, string.ReferenceEquals(str2, str3));//false

            //string.ReferenceEquals(objA,objB);调用的是object类的ReferenceEquals,就是返回objA==objB的值
            //string类进行了运算符重载,==用来比较两个字符串的值是否相等
            //结果是 str1,str2指向同一个对象,跟str3不同

            Console.ReadKey();

}M8N8NM_8]0874DC1559{2N.jpg (9.88 KB, 下载次数: 43)

}M8N8NM_8]0874DC1559{2N.jpg

作者: 阿磊-_-    时间: 2012-9-16 14:58
徐宏伟 发表于 2012-9-6 21:09
我觉得net该有这么一个优化……new的时候会增加,但是直接那么赋值的话,觉得该是一个,但是没有理论依据 ...

是啊,反正我看杨老师视频是这么讲的!  
作者: 阿磊-_-    时间: 2012-9-16 15:02
王海舟 发表于 2012-9-6 23:19
非常感谢你的回复,看来string类型比我理解的更为特殊一些,不仅是不可变类型,在直接赋值的时候都会和普 ...

我说的前提就是赋同一个字符串的时候,变量都是指向同一块区域。你再赋456.新字符串当然重新分配
作者: 张青江    时间: 2012-9-16 15:20
咱们回到问题上来
对象,确实创建了3个。
那么他们三个是什么关系? 对,三个对象的值是相同的,所以他们指向的内存空间是一个。只占用一块地方。
作者: 冯超    时间: 2012-9-16 15:23
怎么发现 前辈是勇的c#进行的




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