String s="abc";
String s1=new String("abc");
String s2=new String("a"+"b"); 
一共创建了几个对象?

解决方案 »

  1.   

    String s1=new String("abc"); 为例  首先你要理解constant   pool,   这是一个特殊的共享区域,literate,   Class这些可以在内存中共享的不经常改变的东西,都可以放在这里。   
      如果你用了String   s1   =   new   String("abc");   
      那么,会有两个String被创建,一个是你的Class被CLassLoader加载时,你的"abc"被作为常量读入,在constant   pool里创建了一个共享的"abc"   
      然后,当调用到new   String("abc")的时候,会在heap里创建这个new   String("abc");   
        
        
      但是如果你把String   s1   =   new   String("abc").intern();   
      那么具体过程变成,现在heap里创建一个String,   然后调用intern()方法,发现constant   pool里存在'abc',然后就会返回constant   pool内对象的引用,稍后heap里的就not   reachable了,会被gc,最终VM里只有一个"abc"
      

  2.   

    String s="abc";在这个中.创建了两个对象,一个是字符串对象:"abc",另一个是String对象s.String s1=new String("abc"); 这个与上面的一个.也是两个.下面的
    String s2=new String("a"+"b"); 
    是三个了.因为多了一个"a","b"有两个对象..再加上s2,就是三个了..
      

  3.   

    楼上讲得太深入了,俺对java还没这样的深度,个人觉得应该是3个吧,至少我们能够感知到的应该是这样,至于jvm里面有什么操作,创建了几个应该不怎么重要吧
      

  4.   

    所谓创建,是指内存的占有
    这里
    String s="abc"; 
    创建一个,并让s句柄指向它
    String s1=new String("abc"); 
    这里创建了两个,一个是"abc",另一个就是new出来的,但是这里的"abc"和s是在同一个地方的,所以这两句加起来还是两个
    String s2=new String("a"+"b"); 这里一共创建了4个
    "a","b","a"+"b",以及new出来的
    所以如果这三句是连在一起的,那么它一共创建了6个string对象
      

  5.   


    应该是4个,这里"a"+"b"被优化成"ab",所以"a","b"没被创建
      

  6.   

    答:在编译时,a"+"b"已经被优化成了"ab".这个+号操作符实际上编译完成后已不存在了.
      

  7.   

    3个或4个String s="abc";  //可能创建了一个对象,或者没有创建。
    String s1=new String("abc"); //创建了一个对象
    String s2=new String("a"+"b"); //创建了一个对象
      

  8.   

    个人认为是三个
    String s="abc"; 这里创建一个abc
    String s1=new String("abc");  这里还是创建一个abc只是和第一个内在位置不同
    String s2=new String("a"+"b"); 这里创建一个ab
    新学的..可能考虑的没那么多~~我感觉就是这样了哈哈
      

  9.   

    作者问题实际上可以理解为"abc"与new String("abc")的区别,所涉及的知识点如下:1.引用变量与对象的区别
      String s = new String("abc");此语句中的s仅仅只是一个引用变量,它不是对象。2.java中所有的字符串都是一个String的对象,即"abc"就是一个String对象。3.字符串对象是怎么创建的?
      由于String对象使用的比较频繁,java为了节省内存空间跟运行效率,在编译区间对字符串常量进行了优化,就是把所有的字符串常量放到了常量池,常量池的好处是该池中的所有相同的字符串常量被合并,并只占一个空间。我知道,对两个引用变量使用==可以判断它们的值(引用)是否相等,即可以判断它们是否指向同一对象:
    public class String1 { public static void main(String[] args) {
    String s1 = "abc";
    String s2 = "abc";
    if(s1 == s2)
    System.out.println("1");
    else
    System.out.println("2"); }}
    输出的结果:1   表明两个字符串常量实际上保存为一个对象,即上面的代码实际上只创建了一个String对象现在看String s = new String("abc");语句,这里"abc"就是constant pool中的一个对象,而在运行的时候执行new,将constant中的对象copy一份到heap(堆)中,并把heap中的这个对象的引用赋给s,所以这条语句就创建了2个String对象现在看下面程序:
    public class String2 { public static void main(String[] args) {
    String s1 = new String("abc");
    String s2 = new String("abc");
    if(s1 == s2)
    System.out.println("1");
    else
    System.out.println("2"); }}
    输出的结果:2
    那么现在上面的代码创建了几个String 对象呢? (三个,constant pool 一个,heap中两个)
    再来看看字符串+和字符串转换的问题,涉及的知识点:
    1.字符串运算符(+,+=,java中唯一重载的两个运算符,java不支持运算符重载):如果一个操作数/表达式是String类型,则另一个操作数在运行时要先转换成String对象,并两者串接。看一程序段:
    String s = new String("abc");
    s = 1+2+s+3+4;
    请问一共创建了多少String对象?如果涉及基本数据类型,则会先转换成包装器类,然后调用toString()方法,我们知道几个包装器类都改写了从Object祖宗类继承的toString()方法(如果是null,则转换为"null"),关于+是串接还是加法,由操作数决定,所以很显然最后结果s="3abc34"。那按照我上面的说话,语句似乎就应该生成5个String对象,即:
    1+2=3,then 3->Integer(3)->"3"in constant
    "3"+s(in heap)="3abc"(in heap)
    "3abc"+3,first 3->Integer(3)->"3"in constant then "3abc3"
    同样"3abc3"+4 then "3abc34"
    但这个结果我不知道是不是正确,希望哪位高人指点下!
    根据上面所述,应该是7个
    String s="abc"; //1个,在constant pool中 
    String s1=new String("abc"); 两个,一个在heap,一个在constant pool
    String s2=new String("a"+"b"); 四个,三个在constant pool,一个在heap
      

  10.   

    楼上的分析很详细。up
    个人比较赞同楼上的:String s="abc"; //1个,在constant pool中 
                        String s1=new String("abc"); 两个,一个在heap,一个在constant pool 
                      String s2=new String("a"+"b"); 四个,三个在constant pool,一个在heap 
      

  11.   

    刚copy快了,
    String s2=new String("a"+"b"); 个人认为是三个。
      

  12.   


    System.out.println(s.hashCode());
    System.out.println(s1.hashCode());
    System.out.println(s2.hashCode());96354
    96354
    3105是否可以证明:至少s跟s1是同一对象呢!
      

  13.   

    String s="abc"; 一个对象“abc”在常量池中String s1=new String("abc");本来是两个对象,常量池中的“abc“,堆中的new String("abc"),但是常量池中“abc”已经创建了,不会在创建,所以这一次只有一个String s2=new String("a"+"b"); 两个对象,常量池中的“ab“,堆中的new String("ab"),不会有“a”,“b","a"+"b"常量池中自动优化为“ab”总共4个
    真搞不明白,为什么有人喜欢把 引用当成对象
      

  14.   

    那按照我上面的说话,语句似乎就应该生成5个String对象,即: 
    1+2=3,then 3->Integer(3)->"3"in constant 
    "3"+s(in heap)="3abc"(in heap) 
    "3abc"+3,first 3->Integer(3)->"3"in constant then "3abc3" 
    同样"3abc3"+4 then "3abc34" 
    但这个结果我不知道是不是正确,希望哪位高人指点下! 这个结果是正确的...
      

  15.   

    up
     
    单独就String s2=new String("a"+"b"); 的话,是不是也像你说的常量池自动优化为"ab",
    那是不是等价于String s2=new String("ab"); 
      

  16.   

    其实问题的关键就在String与+。
    编译器对string + 基本类型是当成常量表达式直接求值来优化的。最后结果是4个,
    30楼是正解
      

  17.   

    那你的意思就是确定3->Integer(3)->"3",此时的"3"也是在constant pool中的?
    哪里可以找到相应的资料没?
      

  18.   

    各位是String Pool 吧,不是constant Pool 吧.....个人认为是四个,因为我参加过的面试有问过这个问题的....
      

  19.   

    一共6个
    s, abc, s1, s2, a, b
      

  20.   


    hashcode不是对地址的一种标志吗?的确相同的hashcode并不代表地址相同,但不同的hashcode就代表不同内存地址了……
      

  21.   

    学习了,但是其中的:

    那按照我上面的说话,语句似乎就应该生成5个String对象,即: 
    1+2=3,then 3->Integer(3)->"3"in constant 
    "3"+s(in heap)="3abc"(in heap) 
    "3abc"+3,first 3->Integer(3)->"3"in constant then "3abc3" 
    同样"3abc3"+4 then "3abc34" 

    这段还是不明白,感觉不是5个,heap中的“abc","3abc","3abc3"和"3abc34"算几个呀?那如果考虑30楼的优化呢?盼高人指点……
      

  22.   

    个人觉的5楼的正确内存中有一块特殊的空间-----字符串池 它只存放“”声明的东西
    1.String s="abc";
      这时  jvm会先去字符串池中找,没有找到,所以会在字符串池中先创建一个“hello” 并用s指向它
    2.String s1=new String("abc");
      这个创建了两个对象 一个是s1 另一个是 “abc” 但是字符串池中有了 所以s1也会指向它,
       所以其实前两个创建了2个对象 
    3.String s2=new String("a"+"b");
      个人觉得 这里一共创建了4个
    "a","b","a"+"b",s2
      

  23.   

    如果"a"+"b" 被优化了 那么"a" ,"b"还会被创建吗?
      

  24.   


    一共创建了四个对象。对于前两句,很多人都没有异意,是创建了两个。
    最关键的在第三句。
    关于"a"+"b"是创建了几个对象。
    字符串常量在字符串池中存放时是按Char[]进行存放的。
    如果字符串常量进行相加,就会创建"ab"放入字符串池。
    所以一共是四个。
    个人愚见。
      

  25.   

    String s="abc"; 
    池中创建"abc"一个对象String s1=new String("abc"); 
    new在堆中创建了一个对象,池中由于第一句已经创建了"abc"对象,所有这句只创建一个对象String s2=new String("a"+"b");
    池中创建共创建"a","b","ab"三个对象,new在堆中创建一个对象所以上面3个语句共创建1+1+4=6个对象

      

  26.   

    Constant Pool常量池的概念:在讲到String的一些特殊情况时,总会提到String Pool或者Constant Pool,但是我想很多人都不太
    明白Constant Pool到底是个怎么样的东西,运行的时候存储在哪里,所以在这里先说一下Constant Pool的内容.
    String Pool是对应于在Constant Pool中存储String常量的区域.习惯称为String Pool,也有人称为
    String Constant Pool.好像没有正式的命名??在java编译好的class文件中,有个区域称为Constant Pool,他是一个由数组组成的表,类型
    为cp_info constant_pool[],用来存储程序中使用的各种常量,包括Class/String/Integer等各
    种基本Java数据类型,详情参见The Java Virtual Machine Specification 4.4章节.
    对于Constant Pool,表的基本通用结构为:
    cp_info {
            u1 tag;
            u1 info[];
    }
    tag是一个数字,用来表示存储的常量的类型,例如8表示String类型,5表示Long类型,info[]根据
    类型码tag的不同会发生相应变化.对于String类型,表的结构为:
    CONSTANT_String_info {
            u1 tag;
            u2 string_index;
    }tag固定为8,string_index是字符串内容信息,类型为:
    CONSTANT_Utf8_info {
            u1 tag;
            u2 length;
            u1 bytes[length];
    }tag固定为1,length为字符串的长度,bytes[length]为字符串的内容.(以下代码在jdk6中编译)
    为了详细理解Constant Pool的结构,我们参看一些代码:
        String s1 = "sss111";
        String s2 = "sss222";
        System.out.println(s1 + " " + s2);由于"sss111"和"sss222"都是字符串常量,在编译期就已经创建好了存储在class文件中.
    在编译后的class文件中会存在这2个常量的对应表示:
    08 00 11 01 00 06 73 73 73 31 31 31 08 00 13 01 ; ......sss111....
    00 06 73 73 73 32 32 32                         ; ..sss222根据上面说的String常量结构,我们分析一下
    开始的08为CONSTANT_String_info结构中的tag,而11应该是它的相对引用,01为
    CONSTANT_Utf8_info的tag,06为对应字符串的长度,73 73 73 31 31 31为字符串对
    应的编码,接着分析,会发现后面的是对应"sss222"的存储结构.
    经过上面分析,我们知道了11和13是两个字符串的相对引用,就可以修改class文件
    来修改打印的内容,把class文件中的
    00 6E 00 04 00 03 00 00 00 24 12 10 4C 12 12 4D
    改成
    00 6E 00 04 00 03 00 00 00 24 12 10 4C 12 10 4D
    程序就会输出sss111 sss111,而不是和原程序一样输出sss111 sss222,因为我
    们把对"sss222"的相对引用12改成了对"sss111"的相对引用10.
    ------------分割线
    public class Test {
        public static void main(String[] args) {
            String s1 = "sss111";
            String s2 = "sss111";
        }
    }在上面程序中存在2个相同的常量"sss111",对于n个值相同的String常量,在Constant Pool中
    只会创建一个,所以在编译好的class文件中,我们只能找到一个对"sss111"的表示:
    000000abh: 08 00 11 01 00 06 73 73 73 31 31 31             ; ......sss111
    在程序执行的时候,Constant Pool会储存在Method Area,而不是heap中.另外,对于""内容为空的字符串常量,会创建一个长度为0,内容为空的字符串放到Constant Pool中,
    而且Constant Pool在运行期是可以动态扩展的.
    关于String类的说明
    1.String使用private final char value[]来实现字符串的存储,也就是说String对象创建之后,就不能
    再修改此对象中存储的字符串内容,就是因为如此,才说String类型是不可变的(immutable).2.String类有一个特殊的创建方法,就是使用""双引号来创建.例如new String("i am")实际创建了2个
    String对象,一个是"i am"通过""双引号创建的,另一个是通过new创建的.只不过他们创建的时期不同,
    一个是编译期,一个是运行期!3.java对String类型重载了+操作符,可以直接使用+对两个字符串进行连接.4.运行期调用String类的intern()方法可以向String Pool中动态添加对象.String的创建方法一般有如下几种
    1.直接使用""引号创建.
    2.使用new String()创建.
    3.使用new String("someString")创建以及其他的一些重载构造函数创建.
    4.使用重载的字符串连接操作符+创建.例1
        /*
        * "sss111"是编译期常量,编译时已经能确定它的值,在编译
        * 好的class文件中它已经在String Pool中了,此语句会在
        * String Pool中查找等于"sss111"的字符串(用equals(Object)方法确定),
        * 如果存在就把引用返回,付值给s1.不存在就会创建一个"sss111"放在
        * String Pool中,然后把引用返回,付值给s1.
        * 
        */
        String s1 = "sss111";    //此语句同上
        String s2 = "sss111";    /*
        * 由于String Pool只会维护一个值相同的String对象
        * 上面2句得到的引用是String Pool中同一个对象,所以
        * 他们引用相等
        */
        System.out.println(s1 == s2); //结果为true
    例2
        /*
        * 在java中,使用new关键字会创建一个新对象,在本例中,不管在
        * String Pool中是否已经有值相同的对象,都会创建了一个新的
        * String对象存储在heap中,然后把引用返回赋给s1.
        * 本例中使用了String的public String(String original)构造函数.
        */
        String s1 = new String("sss111"); 
        
        /*
         * 此句会按照例1中所述在String Pool中查找
         */
        String s2 = "sss111";
        
        /*
         * 由于s1是new出的新对象,存储在heap中,s2指向的对象
         * 存储在String Pool中,他们肯定不是同一个对象,只是
         * 存储的字符串值相同,所以返回false.
         */
        System.out.println(s1 == s2); //结果为false
    例3
        String s1 = new String("sss111"); 
        /*
        * 当调用intern方法时,如果String Pool中已经包含一个等于此String对象
        * 的字符串(用 equals(Object)方法确定),则返回池中的字符串.否则,将此
        * String对象添加到池中,并返回此String对象在String Pool中的引用.
        */
        s1 = s1.intern();
        
        String s2 = "sss111";
        
        /*
         * 由于执行了s1 = s1.intern(),会使s1指向String Pool中值为"sss111"
         * 的字符串对象,s2也指向了同样的对象,所以结果为true
         */
        System.out.println(s1 == s2);
    例4
        String s1 = new String("111"); 
        String s2 = "sss111";
        
        /*
        * 由于进行连接的2个字符串都是常量,编译期就能确定连接后的值了,
        * 编译器会进行优化直接把他们表示成"sss111"存储到String Pool中,
        * 由于上边的s2="sss111"已经在String Pool中加入了"sss111",
        * 此句会把s3指向和s2相同的对象,所以他们引用相同.此时仍然会创建出
        * "sss"和"111"两个常量,存储到String Pool中.    */
        String s3 = "sss" + "111";
        
        /*
         * 由于s1是个变量,在编译期不能确定它的值是多少,所以
         * 会在执行的时候创建一个新的String对象存储到heap中,
         * 然后赋值给s4.
         */
        String s4 = "sss" + s1;
        
        System.out.println(s2 == s3); //true
        System.out.println(s2 == s4); //false
        System.out.println(s2 == s4.intern()); //true
    例5
    这个是The Java Language Specification中3.10.5节的例子,有了上面的说明,这个应该不难理解了
        package testPackage;
        class Test {
                public static void main(String[] args) {
                        String hello = "Hello", lo = "lo";
                        System.out.print((hello == "Hello") + " ");
                        System.out.print((Other.hello == hello) + " ");
                        System.out.print((other.Other.hello == hello) + " ");
                        System.out.print((hello == ("Hel"+"lo")) + " ");
                        System.out.print((hello == ("Hel"+lo)) + " ");
                        System.out.println(hello == ("Hel"+lo).intern());
                }
        }
        class Other { static String hello = "Hello"; }    package other;
        public class Other { static String hello = "Hello"; }输出结果为true true true true false true,请自行分析!
      

  27.   


    String s="abc"; 
    String s1=new String("abc"); 
    String s2=new String("a"+"b");第一句,在栈池中产生一个abc的字符串对象      第1个。第二句,首先在栈池中搜索是否存在值为abc字符串对象的,由于第一句已经创建了,所以不会创建第二次而引用第一次创建的,之后在堆池中创建String对象。 这里是第2个。第三句,首先在栈池中搜索是否存在值为"a"和"b"的对象,由于不存在,所以这里会创建2个对象,之后进行+号连接,这里会创建一个新的对象存储连接之后的字符串"ab",之后再在堆池中创建String对象。所以第三句总共在内存中创建了4个对象。所以加起来应该是6个对象。
      

  28.   


    String s="abc"; 
    String s1=new String("abc"); 
    String s2=new String("a"+"b");第二句总共是一个对象看来没有异议了,第三句呢在string pool 中创建“a”,“b”和“ab”三个对象,所以总共有4个对象!
      

  29.   

    这个总共产生三个对象。s,s1,s2各自有各自的内存空间。
    如果改为:
    String s="abc";
    String s1="abc";
    String s2=new String("a"+"b");  
    则是两个对象了。new能申请新的内存。
      

  30.   

    用new关键字  它会重新创建一个内存空间
    String s="abc";
    String s1=new String("abc");
    String s2=new String("a"+"b");  
    这里用了两个new 说明有两个是肯定的
    第一句  也是一个内存空间~
    如果我创建 一个  String s2=“abc”
    这样还是一个内存空间,
    因为 s1和s2的值是一样的 所以被分配在一个内存空间里~