今天学到String类型 和 池的概念把我给弄糊涂了1.String tmp1 = "abc";
//这样在池中创建了"abc"的String对象,然后tmp1指向"abc"
tmp1--->"abc"2.String tmp2 = new String("abc");
//tmp2指向在堆中新创建的String对象。该对象是保存abc的值 还是再指向池中的"abc"?tmp2--->堆中对象(值为abc)ortmp2--->堆中对象--->池中"abc"
3.String s1 = "1";
  String s2 = "2";
  String s3 = s1+s2;   
//网上说在池中创建了"1"和"2"的对象  然后通过StringBuffer进行+处理再用.toString()放回给s3那么s3就是指向堆中的一个String对象。那那个String对象的值为"12"还是再在池中创个"12"对象,让堆中对象指向"12"。 还是上面2的那个问题4.什么情况下String对象需要放到池中,什么时候不要?
比如  S1.substring(); s1.toUpperCase(); 产生的新值都要放到池中?

解决方案 »

  1.   

    2.String tmp2 = new String("abc"); 
    //tmp2指向在堆中新创建的String对象。该对象是保存abc的值 还是再指向池中的"abc"? tmp2--->堆中对象(值为abc) 本人认为是这个。or tmp2--->堆中对象--->池中"abc" ---------------------要new String对象时在堆中分配,直接赋字符串(如String tmp1 = "abc";)则分配在池中。
      

  2.   

    1 是指向池中的一个地址
    2 是在池中创建一个新的空间,里面存放abc
    3 stringBuffer不用创建新的空间,只是指向一个地址。
    对于4的问题,我也说不清楚,以上是我的理解,不知道对不对,期待紫竹大哥给出正解,和楼主一起学习中。
    up
      

  3.   

    tmp2指向在堆中新创建的String对象。该对象是保存abc的值 还是再指向池中的"abc"?
    ---------在堆中另开辟空间存储"abc”,tmp2引用指向“在堆中另开辟空间存储的"abc”。”而不是池中的!
      

  4.   


    对于你的2,3我认为是错的2我的认为跟楼上一样3 编译后是:   s3 = (new StringBuffer()).append(s1)append(s2).toString(); 
    这样还能没创建对象????至少是两个对象  一个是临时的SB 一个是toString转后出来的对象
      

  5.   

    字面常量String会放入池中。比如“abc”,“1”,“2”这些常量会放进去 
    1.String tmp1 = "abc";
    //这样在池中创建了"abc"的String对象,然后tmp1指向"abc"
    tmp1--->"abc"是的
    2.String tmp2 = new String("abc");
    //tmp2指向在堆中新创建的String对象。该对象是保存abc的值 还是再指向池中的"abc"?
    首先确定一点,tmp2指向的堆中的对象,它是通过new创建的。现在有2个对象了。
    然后去看String类的构造方法,通过看String(String orig)这个构造方法的实现可以知道原理。String中使用字符数组保存实际的字符。public String(String original) {
    int size = original.count;
    char[] originalValue = original.value;
    char[] v;
       if (originalValue.length > size) {
          // The array representing the String is bigger than the new
          // String itself.  Perhaps this constructor is being called
          // in order to trim the baggage, so make a copy of the array.
                int off = original.offset;
                v = Arrays.copyOfRange(originalValue, off, off+size);
      } else {
          // The array representing the String is the same
          // size as the String, so no point in making a copy.
        v = originalValue;
      }
    this.offset = 0;
    this.count = size;
    this.value = v;
        }看这个处理可以知道,两中情况,一种是为这个新的串新创建一个字符数组,一种是直接让这两个串来共享数组。结论: 
    tmp2--->堆中对象(值为abc)当然,两个对象(new得到的堆里的对象,和池里的“abc”对象)是否共享char数组并不重要,关键知道是两个不同的对象即可。
    3.String s1 = "1";
      String s2 = "2";
      String s3 = s1+s2; 
    //网上说在池中创建了"1"和"2"的对象  然后通过StringBuffer进行+处理再用.toString()放回给s3
    在jdk1.5之前是使用StringBuffer来处理的,1.5开始是使用的StringBuilder.
    String s3=s1+s2;
    实际处理为
    StringBuilder builder = new StringBuilder();
    builder.append(s1);
    builder.append(s2);
    String s3=builder.toString();
    去看StringBuilder的 toString()方法: public String toString() {
            // Create a copy, don't share the array
    return new String(value, 0, count);
        }可以发现是通过new String(..)返回了一个String对象,也就是说在堆中创建了对象。这时候不会在池中出现“12”这个对象。//
    那么s3就是指向堆中的一个String对象。4.什么情况下String对象需要放到池中,什么时候不要?
    常量值,也就是使用""括起来的字面常量值会放入常量池 。
    或者你通过String的 intern()方法把一个字符串主动放入常量池。
    比如  S1.substring(); s1.toUpperCase(); 产生的新值都要放到池中,它们产生的串不会放入常量池。
      

  6.   


    您的意思是说 s1.substring();s1.toUpperCase();方法体里最后由this.intern()将产生的新字符串加到池中? 什么叫新值放到池中,新串不放。我在网上看到一遍文章说 编译器对s=s1+s2的优化的。用StringBuffer   
    但只有jdf1.5对次做优化  以前的不用
    链接:http://tech.sina.com.cn/s/2008-07-04/0950720255.shtml
      

  7.   

    比如  S1.substring(); s1.toUpperCase(); 产生的新值都要放到池中,
    前面半句是引用楼主的话,是错误的,我的话是后面半句“它们产生的串不会放入常量池”。
    你想放进去,也好自己通过 s1=s1.intern();这样处理。你给点那个网页上说法,你自己先把所有的代码测试一下,看他说的对吗
      

  8.   

    所谓优化就是使用StringBuilder来处理链接运算而已 。
      

  9.   


    恩 我基本理解了但还是有一点搞不通,就是那片文章上说对于JDK1.5作的优化我测试了,结果都是一样的。   
    不知道1.4用不用buffer 作处理。我实在是看不出来 请您指点!
      

  10.   


    public class Test
    {
        public static void main(String[] args)
        {
             
    String a="a";
            String b="b";
            String c=a+b;
        }}
    javac Test.java
    javap -c TestCompiled from "Test.java"
    public class Test extends java.lang.Object{
    public Test();
      Code:
       0: aload_0
       1: invokespecial #1; //Method java/lang/Object."<init>":()V
       4: returnpublic static void main(java.lang.String[]);
      Code:
       0: ldc #2; //String a
       2: astore_1
       3: ldc #3; //String b
       5: astore_2
       6: new #4; //class java/lang/StringBuilder
       9: dup
       10: invokespecial #5; //Method java/lang/StringBuilder."<init>":()V
       13: aload_1
       14: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       17: aload_2
       18: invokevirtual #6; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       21: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
       24: astore_3
       25: return} 看里面出现的StringBuilder.append
    1.4同样分析
      

  11.   

    String tmp2 = new String("abc"); 
    如果是main方法第一行的话将创建两个String对象,一个是在pool里面,一个是堆里面的。String temp1 = "abc";
    String tmp2 = new String("abc"); //这样的话这句话就只创建一个String对象,是指向堆里的,java里面new出来的东西总是放堆里的。
      

  12.   

    今天又回来看了一通这个帖子,受益匪浅,总结总结,还请ZangXT等各位大侠指正
    1. String str1 = "abc";
       System.out.println(str1 == "abc");
    步骤:
    1) 棧中开辟一块空间存放引用str1,
    2) String池中开辟一块空间,存放String常量"abc",
    3) 引用str1指向池中String常量"abc",
    4) str1所指代的地址即常量"abc"所在地址,输出为true2. String str2 = new String("abc");
       System.out.println(str2 == "abc");
    步骤:
    1) 棧中开辟一块空间存放引用str2,
    2) 堆中开辟一块空间存放一个新建的String对象"abc",该对象与池中的String常量"abc"是否共享char数组,并不重要
    3) 引用str2指向堆中的新建的String对象"abc",
    4) str2所指代的对象地址为堆中地址,而常量"abc"地址在池中,输出为false3. String str3 = new String("abc");
       System.out.println(str3 == str2);
    步骤:
    1) 棧中开辟一块空间存放引用str3,
    2) 堆中开辟一块新空间存放另外一个(不同于str2所指)新建的String对象,该对象与池中的String常量"abc"是否共享char数组,并不重要
    3) 引用str3指向另外新建的那个String对象
    4) str3和str2指向堆中不同的String对象,地址也不相同,输出为false4. String str4 = "a" + "b";
    步骤:
    1) 棧中开辟一块空间存放引用str4,
    2) 堆中开辟一块空间存放一个新建的String对象"ab",String池中并未开辟一块新的空间存放String常量"ab",
    3) 引用str4指向堆中新建的String对象,该对象与池中的String常量"abc"是否共享char数组,并不重要5. String str5 = "abc".substring(0, 2);
    步骤:
    1) 棧中开辟一块空间存放引用str5,
    2) 堆中开辟一块空间存放一个新建的String对象"ab"(不同于str4所指),池中仍然并未开辟新的空间存放String常量"ab",
    3) 引用str5指向堆中的新建String对象,同上,该对象与池中的String常量"abc"是否共享char数组,并不重要6. String str6 = "abc".toUpperCase();
    步骤:
    1) 棧中开辟一块空间存放引用str6,
    2) 堆中开辟一块空间存放一个新建的String对象"ABC",池中并未开辟新的空间存放String常量"ABC",
    3) 引用str6指向堆中的新建String对象