下面这条语句一共创建了多少个对象:String s="a"+"b"+"c"+"d"我觉得应该有 a b ab c abc d abcd七个,但是也有人说是四个,两个,还有一个五个的
我用debug下断点一看居然只有四个 a b c d,是不是测试方法有误,,求大神给出令人信服的答案

解决方案 »

  1.   

    我觉得是一个,但是不太确定
    javap -c是这样的
    public class tyj {
      public tyj();
        Code:
           0: aload_0       
           1: invokespecial #1                  // Method java/lang/Object."<init>":()V
           4: return          public static void main(java.lang.String[]);
        Code:
           0: ldc           #2                  // String abcd
           2: astore_1      
           3: return        
    }坐等楼下高手了
      

  2.   

    我觉得应该是4个,String s="a"+"b"+"c"+"d"
    可以分成下面几部来看:
    String s = "a";
    String b = "b";
    String c = "c";
    String d = "d";
    String s += b + c + d;因为我的理解是第一步的声明s时,已经给它赋值"a",然后按上面我写的代码这么来看,"b","c","d",这正好是三个对象,而最后的s虽然做了拼接操作,但是s还是原来的那个对象,所以最后一共正好有四个
      

  3.   

    就创建了一个, 右边的都是都是常量,只有在将后面的几个常量组合成了abcd之后赋给s时才会去创建对象,与楼上说的那种理解是不同的,如果你的问题是:string a="a";string s=a+"b";那肯定就是创建了3个对象,也就是说,如果是几个常量相加,那么加起来之后赋值时才变成对象, 如果是常量与既有对象相加,那么常量会先变成对象
      

  4.   

    那就是先“+”,再用“=”,那么,”s“和“"a"+"b"+"c"+"d"”是不是也属于同一个对象呢?因为他们对应的地址是一样的呵呵,我说的对么,楼主?共同进步呀,嘿嘿嘿
      

  5.   

    问题1: String s = "a" + "b" + "c" + "d" + "e"; 
    问此语句共创建了几个对象, 答案是 
    就创建了一个 
    String s = "a" + "b" + "c" + "d" + "e"; 
    赋值符号右边的"a"、"b"、"c"、"d"、"e"都是常量 
    对于常量,编译时就直接存储它们的字面值而不是它们的引用 
    在编译时就直接讲它们连接的结果提取出来变成了"abcde" 
    该语句在class文件中就相当于String s = "abcde" 
    然后当JVM执行到这一句的时候, 就在String pool里找 
    如果没有这个字符串,就会产生一个 
      

  6.   

    问题2:但是如果改成 String s = a+b+c+d+e; 
    呢 又是几个了。 就是说上面是一个是因为 "a"、"b"、"c"、"d"、"e"都是常量 
    但如果是变量呢? 我的答案是3个对象,但只有一个String对象:由于编译器的优化,最终代码为通过StringBuilder完成:1.StringBuilder builder = new StringBuilder(); 2.builder.append(a); 3.builder.append(b); 4.builder.append(c); 5.builder.append(d); 6.builder.append(e); 7.String s = builder.toString(); 8.我们先看看StringBuilder的构造器1.    public StringBuilder() {2.      super(16);3.    }看下去1.    AbstractStringBuilder(int capacity) {2.        value = new char[capacity];3.    }可见,分配了一个16自己长度的char数组我们看看append的整个过程(注意,源代码我从各个类进行了整合,他们实际上不在一个类里面的)1.2.  public StringBuilder append(String str) {3.    super.append(str);4.    return this;5.  }6.7.  public AbstractStringBuilder append(String str) {8.    if (str == null)9.      str = "null";10.    int len = str.length();11.    if (len == 0)12.      return this;13.    int newCount = count + len;14.    if (newCount > value.length)15.      expandCapacity(newCount);16.    str.getChars(0, len, value, count);17.    count = newCount;18.    return this;19.  }20.21.  public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {22.    if (srcBegin < 0) {23.      throw new StringIndexOutOfBoundsException(srcBegin);24.    }25.    if (srcEnd > count) {26.      throw new StringIndexOutOfBoundsException(srcEnd);27.    }28.    if (srcBegin > srcEnd) {29.      throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);30.    }31.    System32.        .arraycopy(value, offset + srcBegin, dst, dstBegin, srcEnd - srcBegin);33.  }可见,我们的代码不会超过16个,所以不会出现扩展value的情况。而append里面使用了arraycopy的复制方式,也没有产生新的对象。最后,我们再看StringBuilder的 toString()方法: 1. public String toString() {2.    // Create a copy, don't share the array3.    return new String(value, 0, count);4.  }这里通过前面的数组生成了一个新的String。大家注意那个默认的16容量,如果题目出现了总长度超过16,则会出现如下的再次分配的情况1.  void expandCapacity(int minimumCapacity) {
    2.    int newCapacity = (value.length + 1) * 2;
    3.    if (newCapacity < 0) {
    4.      newCapacity = Integer.MAX_VALUE;
    5.    } else if (minimumCapacity > newCapacity) {
    6.      newCapacity = minimumCapacity;
    7.    }
    8.    value = Arrays.copyOf(value, newCapacity);
    9.  }
    10.11.  public static char[] copyOf(char[] original, int newLength) {
    12.    char[] copy = new char[newLength];
    13.    System
    14.        .arraycopy(original, 0, copy, 0, Math.min(original.length, newLength));
    15.    return copy;
    16.  }
    可见,expand容量时,增加为当前(长度+1)*2。
    注意这里用了Arrays的方法,注意不是前面的 System.arraycopy方法哦。这里产生了一个新的
    copy的char数组,长度为新的长度
    总结:三个对象分别为1 StringBuilder2 new char[capacity]3 new String(value,0,count);如果说String对象,则为1个。
      

  7.   


    只有在将后面的几个常量组合成了abcd之后赋给s时才会去创建对象    也就是说最终还是有五个。而且String a=
    “b” 的方式本来就会在串池里创建对象,怎么能说只有一个呢
      

  8.   

    可是我查了好多资料,发现String a= “b” a常量虽然再串池中,但他仍旧是对象类型,也就是说“"a"+"b"+"c"+"d"”有四个常量代表四个对象,那怎么用s指向四个对象呢??我觉得楼上对你的理解有解释
    就是这句             
    对于常量,编译时就直接存储它们的字面值而不是它们的引用 
     在编译时就直接讲它们连接的结果提取出来变成了"abcde" 
     该语句在class文件中就相当于String s = "abcde" 
     然后当JVM执行到这一句的时候, 就在String pool里找 
     如果没有这个字符串,就会产生一个 
      

  9.   


    你说
    对于常量,编译时就直接存储它们的字面值而不是它们的引用 
     在编译时就直接讲它们连接的结果提取出来变成了"abcde" 
     该语句在class文件中就相当于String s = "abcde" 
     然后当JVM执行到这一句的时候, 就在String pool里找 
     如果没有这个字符串,就会产生一个 也就是说最终的s在String pool是对象,那么最初的
    "a" + "b" + "c" + "d"同样在string pool中,那么就不止一个对象了不是吗??
      

  10.   

    注意这一句“该语句在class文件中就相当于String s = "abcde" “
    你再想想,会产生几个?
      

  11.   

    10楼已经解释很清楚答案是 
    就创建了一个 
    String s = "a" + "b" + "c" + "d" + "e"; 
    赋值符号右边的"a"、"b"、"c"、"d"、"e"都是常量 
    对于常量,编译时就直接存储它们的字面值而不是它们的引用 
    在编译时就直接讲它们连接的结果提取出来变成了"abcde" 
    该语句在class文件中就相当于String s = "abcde" 
    然后当JVM执行到这一句的时候, 就在String pool里找 
    如果没有这个字符串,就会产生一个
     
      

  12.   

    http://blog.163.com/leijiangjiahe@126/blog/static/12154679201052443830187/
      

  13.   

    quote=引用 15 楼 lieyanfeng 的回复:]
    引用 14 楼 hc334521 的回复:引用 10 楼 lieyanfeng 的回复:
    问题1: String s = "a" + "b" + "c" + "d" + "e"; 
    问此语句共创建了几个对象, 答案是 
    就创建了一个 
    String s = "a" + "b" + "c" + "d" + "e"; 
    赋值符号右边的"a"、"b"、"c"、……
    我有点乱,你要不用debug断点看一下
    [
      

  14.   

    你看看用debug断点得到的结果
    我不是很明白
      

  15.   

    有可能一个有可能0个  首先我觉得如果你写的是"a"+"b"+"c"+"d"这样的那么编译器在编译期间就会把他优化成"abcd",然后如果缓冲池中有abcd这个字符串的话则不创建这个字符串对象直接把引用指向这个缓冲池中的abcd。如果缓冲池中不存在这个abcd字符串那么就会创建一个字符串这时候是1个。
      

  16.   

    亲,不要纠结这个问题了,纯属浪费时间,不如学学jvm原理。如果不是很熟悉jvm,给出的答案不可信,可以去iteye中的高级虚拟机圈子看看。
      

  17.   

    看了这么多解释 我是不是要说 这个JDK版本有关系
      

  18.   

    只有1个对象。其他是String 池中的分配的
      

  19.   

    我也认为是2个
    一个是s
    一个是abcd
      

  20.   

    但是string类型本身就是一个对象啊而且是final的相加时怎么能当做常量看呢,不知道是不是我的理解偏差,请高手指教
      

  21.   


    是的。java的初始化部分进行了优化,这种情况只创建一次。但是如果"abcd"本来就存在string pool里的话,恐怕就是0个了。
      

  22.   

    0个或者1个,"a"+"b"+"c"+"d"在编译时就会转化为“abcd”,如果缓冲池中有“abcd”字符串了,那么没有创建对象。
      

  23.   

    其实在java真正运行的时候,不是表面上看到的那样,它里面自动引进了StringBuffer类
      

  24.   

    这个前段时间刚看过,当时看的是一个,以为已经理解了,看完了前面的高手我再作出自己的总结性学习吧:
    1.这行代码编译器对他必然会进行优化,优化的方案和编译器的版本可能有关系,高版本的会优化为一个。
    像String s="abcd";但是这仅限于代码到class文件阶段,具体创建和运行的前后程序和运行的虚拟机有关系。
    2.如果这行代码运行之前,内存里面已经存在“abcd”这样的对象,那么就不会再创建这个对象,意思是让我们从另一个角度看,这行代码可能运行在其他环境中,这和虚拟机内部有关系,需要去学习像string对象池这样的内部机制的存在
    3.java虚拟机在运行时,如果string池中不存在该对象,创建“abcd”这个对象时,可能也会创建其他的对象来提高创建目标对象的效率,这些对象具体的实现可能也和jvm版本有关系
    4.根据以上觉得,此题的目的还是第一条,是让我们理解编译器在编译阶段不会做傻瓜似的事,让虚拟机运行时去一个一个的创建对象,而是直接优化代码中的不合理的地方。
    5.另lz在debug中看见的a,b,c,这样的东西,就类似于int 和Integer一样,它可能只是一个值,不是对象
      

  25.   

    我也认为是2个
    一个是s
    一个是abcd 
      

  26.   

    创建了一个, 右边的都是都是常量,只有在将后面的几个常量组合成了abcd之后赋给s时才会去创建对象
      

  27.   

    楼主可以看下下面的文章链接
    http://www.iteye.com/topic/774673
    http://yiliner.iteye.com/blog/207723
    我看过得到的结论就是,像楼主String s="a"+"b"+"c"+"d";这语句在编译时期就可以确定的,这个语句等同于
    String s="abcd";只会在常量池中存在一个对象,即abcd,楼主说在debug时看见的四个对象,其实string的内部实现是char数组,这个可以看下jdk的源码,你看到所谓的四个对象,其实就是string value值的char数组
      

  28.   

    一个对象Java字符串的缓存机制,编译器在编译的时候会进行优化,所以在编译的过程中"a"+"b"+"c"+"d"被合成了一个字符串"abcd",因此,如果缓存池中目前没有"abcd"这个对象,那么会产生一个,即"abcd",且栈中产生一个引用s指向它,如果缓存池中已经存在"abcd",那么将产生0个对象,直接用s指向它。
      

  29.   

    "a"  "b"  "c"  "d"  "e"属于常量存储在常量区域。
    变量不属于对象。
    String 类声明的s才算一个对象。
    所以只有一个对象。
      

  30.   

    这个问题涉及到定义常量和变量的存储关系.在String s=""+"";双引号代表的是匿名常量.在这条语句执行的时候,jvm会在栈区生成abcd四个常量.变量s只是作为一个声明、引用,并没有创建对象。如果在这语句之后又用双引号将a,b,c,d括起来,那么创建对象的总数是多少呢?答案还是一样的,当一个常量存在于栈区的时候,不会再重复创建同值的常量。
      

  31.   

    我想了貌似一个,但是这个对象是s 还是 abcd
      

  32.   

    7个。abcd有4个+("a"+"b")+("a"+"b"+"c")+("a"+"b"+"c"+"d") 共7个
      

  33.   

    你再看下这个链接吧
    http://blog.163.com/luyufen_luise/blog/static/5777392520086230367627/
    s是引用,跟对象不是一个概念的,所以string a=new strin("abc");创建了几个对象,网上的答案是有错误的,无论什么情况,那个a他不是对象,只是string 对象的引用变量
      

  34.   

    class Test { private static void prt(long end, long start) {
    System.out.printf("time:%d%n", end - start);
    } /**
     * java虚拟机对其进行了优化,只有一个对象,
     * 
     * <p>
     * 让我突然想到了一个线程的问题,没有同步,虚拟机将这个代码 <code>while(!done)i++;</code> 被转变成这样
     * <code>if(!done)while(true)i++;</code> 这种优化称作提升(hoisting),擦!扯远了。
     * </p>
     * 
     * time:2194
     * 
     * time:731 连续执行2次a(),第二次执行不再创建对象(除非用new), 对象已经存在于(heap)内存池中
     */
    private void a() {
    long start = System.nanoTime();
    String s = "0" + "1" + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9";
    long end = System.nanoTime();
    prt(end, start);
    } /**
     * 和方法a的时间几乎一样,该方法更加确定了方法a在创建字符串的时候只有一个对象。
     * 
     * time:2194
     */
    private void b() {
    long start = System.nanoTime();
    String s = "0123456789";
    long end = System.nanoTime();
    prt(end, start);
    } /**
     * 哇塞,时间比a多了将近32倍
     * 
     * time:69482
     */
    private void c() {
    // 加入一个变量
    String a = "1";
    //
    long start = System.nanoTime();
    String s = "0" + a + "2" + "3" + "4" + "5" + "6" + "7" + "8" + "9";
    long end = System.nanoTime();
    prt(end, start);
    } /**
     * 时间复杂度为n的2次方(n为相加的字符数量),NEVER DO THIS!
     * 
     * i == 10 time:88133
     * 
     * i == 1000 time:7454010
     */
    public void d() {
    long start = System.nanoTime();
    String s = "0";
    for (int i = 1; i < 1000; i++) {
    s += i;
    }
    long end = System.nanoTime();
    prt(end, start); } /**
     * StringBuilder
     * 
     * i == 10 time:68386
     * 
     * i == 1000 time:529164
     */
    public void e() {
    long start = System.nanoTime();
    StringBuilder s = new StringBuilder("0");
    for (int i = 1; i < 1000; i++) {
    s.append(i);
    }
    long end = System.nanoTime();
    prt(end, start);
    } /**
     * 1个对象
     * 
     * time:2194
     */
    public void f() {
    long start = System.nanoTime();
    String s = "1 Object";
    long end = System.nanoTime();
    prt(end, start);
    } /**
     * 2个对象, "2 Object"是一个对象, new完后s句柄指向的是第二个新创建的对象, 看来new的开销挺虎人呀
     * 
     * time:17919
     */
    public void g() {
    long start = System.nanoTime();
    String s = new String("2 Object");
    long end = System.nanoTime();
    prt(end, start); } public static void main(String[] args) {
    Test t = new Test();
    // 一次只运行一个方法
    // t.a();
    // t.a(); // t.b();
    // t.c();
    // t.d();
    // t.e();
    // t.f();
    t.g(); }}楼主问题结论:只有一个对象,java虚拟机对其进行了优化。
      

  35.   

    对象分为两种:字符串对象和字符串引用对象
    字符串对象是4个,也就是 a  b  c  和  d
    而字符串引用对象是1个,也就是s 
    所以一共是5个对象。
      

  36.   

    0或者1个,你debug看到的应该String内部的Char数组
      

  37.   

    要搞清楚这个问题,首先要搞清楚String类对象是怎样存储与创建的。
    Java常用的存储有三个地方:
    栈——栈是存放引用和基本类型值的地方;
    堆——存储new对象的地方(所有使用new创建的对象都存放在此);
    池——也叫常量存储池,字符串的常量表达式(直接使用"..."创建的字符串)就存储在这个地方。
    String类对象的创建:
    1.String s="abcd"; 
    直接在池中创建一个String类常量对象。
    2.String s=new String("abcd");
    首先判断池中是否有值为abcd的String类常量对象,如果没有则在池中创建一个String类常量对象,之后再在堆中创建一个String对象,引用s指向堆中的对象。
    搞清楚String类对象的创建和存储就弄清了楼主问的问题了。
    String s="a"+"b"+"c"+"d";
    //JVM在编译时对String常量对象(这里不能是非final引用)的+操作符进行了优化
    //因此上面表达式等同于s="abcd",也就是只在池中创建了一个对象;
    String l="abcd";
    String p=new String("abcd");
    System.out.println(s==l);//true s与l都指向池中的String常量对象
    System.out.println(s==p);//false p指向了堆中的String对象11楼的大侠提的问题很好,可以更好的理解String类对象的创建。
    String s="ab";
    String p=s+"cd";//引用s的值在编译时期无法确定,s+"cd"无法在编译时期进行优化
    //JVM中对String对象的+进行了重载,其会先创建一个StringBulder对象
    //之后使用appand方法连接字符串,然后使用toString方法创建为String对象
    //这里至少要创建三个对象,StringBulder、池中的String对象、堆中的String对象(引用p指向此对象)
    String l="abcd";
    System.out.println(l==p);//false p指向了堆中的String对象final String m="ab";
    //String类对象值不可变,final修饰的引用指向不可变,故引用m与String常量值"ab"绑定了
    String n=m+"cd";
    //此时jvm编译时会确定引用m就是String常量对象"ab"
    //这里就等同于n="ab"+"cd",也就等同于n="abcd";
    System.out.println(n==p);//ture n与l都指向了池中的String常量对象String类对象的创建于存储基本就是这个样子,希望大家多多拍砖。
    期望楼主满意,给分吧!
      

  38.   

    常量放在数据区,String s 就这个对象而已!可以再用String w = "a";去测试,因为数据区已经有"a", 已不用生成;"a"+"b"+"c"+"d" 在数据区里取然后连接后在堆里开辟空间存放"abcd";
      

  39.   


    这个断点的意思并不是创建了4个对象
    你用断点跟踪一下String s = "abcd";
    结果和String s = "a"+"b"+"c"+"d";是一样的,你总不能说String s = "abcd";创建了4个对象吧
    这个断点只能说明String对象内部是用一个char []保存String的值,而且char []的长度为4