黑马程序员技术交流社区

标题: 下面这条语句一共创建了多少个对象?为什么?[已解决] [打印本页]

作者: 王自强    时间: 2012-8-31 23:56
标题: 下面这条语句一共创建了多少个对象?为什么?[已解决]
本帖最后由 王自强 于 2012-9-2 17:28 编辑

下面这条语句一共创建了多少个对象:
String s1="a"+"b"+"c"+"d";

为什么?
String s2 = new String("abcd");呢?

作者: 阳杰    时间: 2012-9-1 00:02
就一个吧, 对象只能new出来,我觉得
作者: 王自强    时间: 2012-9-1 00:18
武庆东 发表于 2012-9-1 00:09
String s1="a"+"b"+"c"+"d";//开辟了一个对象,=赋值预算顺序低于+ ,等价于String  s1="abcd"
String s2 = ...

3个?分别在内存中是怎么体现的呢?
作者: 谭海鹏    时间: 2012-9-1 00:36
String s1="a"+"b"+"c"+"d";
相当于直接定义了一个”abcd”的字符串,所以,应该只创建了一个String对象。
原因:javac编译可以对字符串常量直接相加的表达式进行优化,不必要等到运行期去进行加法运算处理,而是在编译时去掉其中的加号,直接将其编译成一个这些常量相连的结果。

String s2 = new String("abcd")
两个对象,一个是“abcd”,一个是指向“abcd”的引用对象,str是存放在栈中的指针,其值“abcd”在堆中!
String("abcd")中的"abcd"在栈中(也就是在s2的下方!)
也就是str和String("abcd")中的"abcd"都在栈中!
而s2指向的"abcd"在堆中!
作者: 王金科    时间: 2012-9-1 00:51
  1. String s1 = "abcd";
  2.                  String s2 = "abcd";
  3.                  String s3 = "ab" + "cd";
  4.                  String s4 = new String("abcd");
  5.                  System.out.println(s1 == s2);//true,因为abcd存在常量池中
  6.                  System.out.println(s1 == s3);//true,因为abcd存在常量池中
  7.                  System.out.println(s1 == s4);//false,new出来的是一个对象,不存在常量池中
复制代码
String s1="a"+"b"+"c"+"d";

这里是一个对象s1, 字符串abcd在常量池中
String s2 = new String("abcd");这里是两个对象:s2, 字符串abcd, new出来的字符串不在常量池中.
我是这样理解的,希望能帮到你
作者: 芦曦    时间: 2012-9-1 00:54
String s1 = "a"+"b"+"c"+"d";+号是连接符,用于连接字符串,所以这句等同于 String s1 ="abcd";这里只创建了一个String对象。
String s2 =new String("abcd");这里创建的是2个对象,new是创建一个对象 ,而"abcd"也是一个对象,所以这句代码在内存中有2个对象。
作者: 张飞年    时间: 2012-9-1 02:29
武庆东 发表于 2012-9-1 00:09
String s1="a"+"b"+"c"+"d";//开辟了一个对象,=赋值预算顺序低于+ ,等价于String  s1="abcd"
String s2 = ...

第二句有问题哦,是两个对象。字符串本身的数据区一个,new的堆内存一个。
作者: 郑义    时间: 2012-9-1 07:55
想要搞明白字符串在内存中的存储情况,除了堆栈还要弄明白一个概念,那就是字符串池(String Pool)。
字符串池:在JVM中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。
                  由于String类是final的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来的程序混乱。
下边通过一个例子进行讲解:
  1. import java.util.*;
  2. class Test1
  3. {
  4. public static void main(String[] args)
  5. {
  6. String str1 = "abc";
  7. String str2 = "a" + "bc";
  8. String str3 = new String("abc");
  9. System.out.println(str1 == str2); //true
  10. System.out.println(str1 == str3); //false
  11. }
  12. }
复制代码
对这个例子的结果肯定是都知道的。这个也是验证字符串在内存中分配的最好的办法。
1、String str1 = "abc";
当程序执行到这句话的时候,首先会创建一个字符串的引用对象str1,然后会创建一个字符串常量。
而这个字符串常量就会存在字符串池,而非堆内存中。
str1引用这个字符串池中的字符串“abc”。
2、String str2 = "a" + "bc";
当程序执行这句话的时候,首先会创建一个字符串的引用对象str2,然后根据字符串的连接规则,又创建了一个字符串常量“abc”。
前边已经说过,字符串池中的内容是可以共享的(为了提高效率),所以并不会在字符串池中重新创建“abc”。
而是让引用对象str2也指向了这个字符串池中的字符串常量“abc”。
3、String str3 = new String("abc");
当程序执行这句话的时候,首先会创建一个字符串的引用对象str3。
这个与上边两句不同的是,这句话是用new关键字来创建字符串的,而并非字符串常量。
所以执行这句话的时候会在堆内存中创建一个新的字符串对象“abc”。此时str3指向这个堆内存中的“abc”。
这要是为什么System.out.println(str1 == str3); 的结果是false的原因。
但是,这里需要说明的是,尽管new一个字符串会在堆内存中创建一个新的对象,
但是在创建这个新的对象之前还要检查在字符串池中有没有与此“abc”相同的字符串。
如果没有就在字符串池中创建一个字符串常量“abc ”在此例子中,前边已经创建过,所以此时不用再创建。

通过上边说的,我感觉你的
第一句创建一个对象,第二句创建两个对象。

作者: 陈莹    时间: 2012-9-1 10:54
郑义 发表于 2012-9-1 07:55
想要搞明白字符串在内存中的存储情况,除了堆栈还要弄明白一个概念,那就是字符串池(String Pool)。
字符 ...


讲的太好了!鼓掌!
作者: AngieFans85    时间: 2012-9-1 13:15
5个对象,分别是:
"a","b","c","d","abcd".
作者: 黑马-李勇    时间: 2012-9-1 13:23
我觉得只有一个对象,abcd
只有new出来的才是一个新的对象吧。
s1,s2只是两个引用。
而常量池中应该只有一个abcd对象。

作者: 赵伟闯    时间: 2012-9-1 16:27
String s="test";
                String j="java";
                String js="testjava";
                String test=s+j; //test 的内存指向?  是不是test分别指向s和j。然后在根据s和j的内存组合成一个字符串
                System.out.println(test==js);  //false  ??
作者: 赵伟闯    时间: 2012-9-1 16:28
郑义 发表于 2012-9-1 07:55
想要搞明白字符串在内存中的存储情况,除了堆栈还要弄明白一个概念,那就是字符串池(String Pool)。
字符 ...

String s="test";
                String j="java";
                String js="testjava";
                String test=s+j; //test 的内存指向?  是不是test分别指向s和j。然后在根据s和j的内存组合成一个字符串
                System.out.println(test==js);  //false  ??
作者: 郑义    时间: 2012-9-1 16:41
赵伟闯 发表于 2012-9-1 16:28
String s="test";
                String j="java";
                String js="testjava";

以我的理解就是
String test = s+j;与String test = "test"+"java";并不相同。
因为第一个是变量相加,应该在堆内存中重新建立一个新的字符串对象。
第二个是常量相加,所以这个字符串还应该是在字符串池当中。
作者: 赵伟闯    时间: 2012-9-1 16:47
郑义 发表于 2012-9-1 16:41
以我的理解就是
String test = s+j;与String test = "test"+"java";并不相同。
因为第一个是变量相加,应 ...

test内存指向是?
作者: 赵伟闯    时间: 2012-9-1 16:48
郑义 发表于 2012-9-1 16:41
以我的理解就是
String test = s+j;与String test = "test"+"java";并不相同。
因为第一个是变量相加,应 ...

也许大概知道了
作者: 刘岩喜    时间: 2012-9-1 22:27
1. String是常量,其对象一旦创建完毕就无法改变。当使用+拼接字符串时,会生成新
的String对象,而不是向原有的String对象追加内容。

2. String Pool(字符串池)
3. String s = “aaa”;(采用字面值方式赋值)
1)  查找String Pool中是否存在“aaa”这个对象,如果不存在,则在String Pool中创建
一个“aaa”对象,然后将String  Pool中的这个“aaa”对象的地址返回来,赋给引
用变量s,这样s会指向String Pool中的这个“aaa”字符串对象
2)  如果存在,则不创建任何对象,直接将String Pool中的这个“aaa”对象地址返回来,
赋给s引用。
4. String s = new String(“aaa”);
1)  首先在String Pool中查找有没有“aaa”这个字符串对象,如果有,则不在String Pool
中再去创建“aaa”这个对象了,直接在堆中(heap)中创建一个“aaa”字符串对
象,然后将堆中的这个“aaa”对象的地址返回来,赋给s引用,导致s指向了堆中
创建的这个“aaa”字符串对象。
2)  如果没有,则首先在String Pool中创建一个“aaa“对象,然后再在堆中(heap)创
建一个”aaa“对象,然后将堆中的这个”aaa“对象的地址返回来,赋给s 引用,
导致s指向了堆中所创建的这个”aaa“对象。
作者: 武庆东    时间: 2012-9-7 13:29
重新梳理一下,发现之前回复的帖子应该错了,大家看一下发表一下意见
下面这条语句一共创建了多少个对象:
String s1=
"a"+"b"+"c"+"d";为什么?
答案:五个个对象  分别为 a 、b、c、d,abcd这三个个对象可能大多数都认同一个对象!但是我觉五个对象的话也能说得通!
解释:
      在JAVA虚拟机(JVM)中存在着一个字符串池,其中保存着很多String对象,并且可以被共享使用,因此它提高了效率。由于String类是final的,它的值一经创建就不可改变,因此我们不用担心String对象共享而带来程序的混乱。


一个String对象内容的改变实际上是通过内存地址的的“断开--连接完成的没有任何变化”
e
大家觉得呢?
  







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