如图所示,Java书里说语句String str = new String("hello"); 会在堆内存中创造两个堆内存空间,除了new出来的那块堆内存,定义字符串常量的堆内存空间是属于没有栈内存引用的垃圾,会被回收。可是我看好多资料里说使用构造方法实例化String对象时候,除了new出来的那个堆内存中的对象,另外一个字符串匿名对象会被保存在字符串常量池中,那这个对象按书里的说法就是垃圾会被gc呀。举例: String s3 = new String("1")  +  new String("1");  表达式第一个操作数我懂,就是开辟了两个对象,一个new出来的堆对象,一个对象放在了字符串常量池里,那么第二个new String("1")也要在堆内存中new一个新对象我懂,我不明白的是第二个操作数,但我看网上说这时候字符串常量池里有1这个对象了,就不需要在开辟一个对象了。我就是在这里想不通,通过第一个new String("1")而在字符串常量池中开辟的对象不算是没有任何栈指向的垃圾么???要是垃圾的话,那么这个匿名对象在第二个new String("1")之前就被gc回收了话怎么办呢?

解决方案 »

  1.   

    我就是很不明白,我看的书也好,网上的资料也好,一会儿说这个"hello"这个字符串是匿名对象会被保存在字符串常量池里,可以供下次重复使用,一会儿又会说这个String类的匿名对象是垃圾,正在等待被gc会被回收。都被回收了还这么重复使用呢?书里还说String str = new String(“hello").intern();
    这样是将new出来的对象入池,可是在执行String str = new String(“hello")的时候已经在字符串常量池里保存了一个hello对象呀,再执行如此入池操作,那么字符串常量池里会有两块内存里存的内容都是hello么???
    这里真是搞糊涂了
      

  2.   

    String str = new String(“hello") str指向内存栈中hello的存储的地址String str = new String(“hello").intern(); 把str 指向 常量池中hello的地址。如果常量池中不存在hello这个常量就生产hello这个常量,并将str指向该地址。
      

  3.   


    应该说在该类结束之前你不用担心被当垃圾回收问题,只有该类结束了gc才会回收常量池中的垃圾。

    谢谢大神的指点但我还是有点不明白,在类结束之前不会被回收的话,那么如果在类A里往字符串常量池里加了一个"hello",那么在另外一个类B里执行语句String str = new String(“hello"),这时候就有可能之前的字符串常量池中的hello已经被回收了对么?
      

  4.   

    public class StringDemo{
        public static void main(String[] args){
              Book bk = new Book();
              bk.test():
            // 请问执行这里的时候,是不是由Book类在字符串常量池里之前存的hello有可能已经被回收了呢?
              String str = new String("hello");
        }
    }
    class Book{
        public void test{
              System.out.println("hello".equals("hello"))
      }
    }
      

  5.   

    public class StringDemo{
        public static void main(String[] args){
              Book bk = new Book();
              bk.test():
            // 请问执行这里的时候,是不是由Book类在字符串常量池里之前存的hello有可能已经被回收了呢?
              String str = new String("hello");
        }
    }
    class Book{
        public void test{
              System.out.println("hello".equals("hello"))
      }
    }确实有可能执行完test();就被回收了。具体过程需要学习jvm机制这类知识。
      

  6.   

    public class StringDemo{
        public static void main(String[] args){
              Book bk = new Book();
              bk.test():
            // 请问执行这里的时候,是不是由Book类在字符串常量池里之前存的hello有可能已经被回收了呢?
              String str = new String("hello");
        }
    }
    class Book{
        public void test{
              System.out.println("hello".equals("hello"))
      }
    }确实有可能执行完test();就被回收了。具体过程需要学习jvm机制这类知识。
    嗯嗯,谢谢大神,大神辛苦了,我还是个菜鸟,等我看完手上这本Java基础语法书,我就去找大神说的书看。那大神我还有两个问题哦,劳烦你了
    第一个:如果这个String str = new String(“hello") 语句是写在某个类的某个方法中的,那它就是个局部变量,那它的作用域就是与方法共存亡(这是菜鸟教程里说的),那么这个方法结束后,但类没结束,这时候由这个语句在字符串常量池里保存的hello会被回收么?
    第二个:String str = new String(“hello").intern(),这句话是不是很没有意义啊,因为就算不把这个str入池,在String str = new String(“hello")的时候也会保存一个hello到字符串常量池中的。
      

  7.   

    可以看一段程序加深理解public class test16 { public static void main(String[] args) {
    // TODO Auto-generated method stub
    String str1 = new String("hello");
    String str2 = new String("hello").intern();
    String str3 = "hello";
    System.out.println(str1 == str2);
    System.out.println(str2 == str3);
    System.out.println(str1 == str3); }}运行结果:false
    true
    false
    因为String str = new String("hello"); str的指向是内存栈中的hello存储地址,字符串常量池中产生的hello是过程量,随时可以能被jvm回收。而String str = new String("hello").intern(); str被指向常量池中的hello地址等价于String str = "hello"; 这个我在3楼时已经说过了,所以2者还是有区别的。
      

  8.   

    这个 String.intern() 分为JDK1.6和1.7以后的区别的
    如果在jdk1.6,那么就将堆中的"str01"添加到常量池中,如果是jdk1.7,那么就在常量池保存指向堆中"str01"的地址。
    String str = new String("str");
    str.intern();检查到常量池不存在"str01",如果在jdk1.6,那么就将堆中的"str"添加到常量池中,如果是jdk1.7,那么就在常量池保存指向堆中"str"的地址。