如图所示,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回收了话怎么办呢?
这样是将new出来的对象入池,可是在执行String str = new String(“hello")的时候已经在字符串常量池里保存了一个hello对象呀,再执行如此入池操作,那么字符串常量池里会有两块内存里存的内容都是hello么???
这里真是搞糊涂了
应该说在该类结束之前你不用担心被当垃圾回收问题,只有该类结束了gc才会回收常量池中的垃圾。
谢谢大神的指点但我还是有点不明白,在类结束之前不会被回收的话,那么如果在类A里往字符串常量池里加了一个"hello",那么在另外一个类B里执行语句String str = new String(“hello"),这时候就有可能之前的字符串常量池中的hello已经被回收了对么?
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"))
}
}
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机制这类知识。
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到字符串常量池中的。
// 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者还是有区别的。
如果在jdk1.6,那么就将堆中的"str01"添加到常量池中,如果是jdk1.7,那么就在常量池保存指向堆中"str01"的地址。
String str = new String("str");
str.intern();检查到常量池不存在"str01",如果在jdk1.6,那么就将堆中的"str"添加到常量池中,如果是jdk1.7,那么就在常量池保存指向堆中"str"的地址。