对于Strings常量池和堆,我有点困惑,我想了解字符串对象何时才有资格进行垃圾回收,因此请考虑以下代码,以准备以下Strings对象中的哪一个在Java中进行垃圾回收?
class Demo{
public static void main(String args[]){
String s1 = new String("hey");
String s2 = s1;
String s3 = "hey";
String s4 = "hey";
String s5 = new String("guys");
String s6 = "guys";
String s7 = "guYs";
s1 = s1.concat("world");
s7 = null;
s8 = null;
}
}
答案 0 :(得分:1)
第一件事:您拥有诸如“ s1”之类的变量,它们是指针(在Java中,为“引用”)。它们就像一张藏宝图:它们本身并不是藏宝,它们只是指向藏宝所在的方向。
在此示例中,变量是藏宝图,字符串是藏宝。
上面的示例总共只有7个宝藏:
“嘿”,“家伙”,“ guYs”,“世界” –这四个宝藏是在加载类时创建的,因为它们实际上位于源代码中。伙计们和伙计们显然是不同的字符串。
第五个宝藏是使用new String("hey")
创建的字符串-这将对宝藏"hey"
的引用传递给字符串构造函数。即使在这里没有意义的练习(即使无法更改字符串,所有构造函数也始终会创造新宝藏)(字符串不能更改,所以有什么意义吧?只是,规则是:调用new
意味着新宝藏,因此就制造了新宝藏)。现在,藏宝图s1
指向独特的藏宝,因此恰好看起来很像藏宝"hey"
。
s2 = s1
只是在复制藏宝图。它带来了与s1相同的宝藏。
s3
成为一个藏宝图,它指向现有的藏宝"hey"
。它和s1和s1所指的是不同的宝藏。
s4
成为与s3相同的藏宝图。
s5
和s6
是s1
与s3
情节的副本:2件宝贝。
s7
与s3 / s4 / s6相同。
然后找到s1
宝藏(s1.
-点是:拿这张宝藏图并找到宝藏),然后要求宝藏执行方法concat
,向其传递对其他宝藏("world"
)的引用。 concat的实现最终会产生另一个宝藏(它将显示为“ heyworld”),并返回指向该新宝藏的宝藏地图。然后,您将指向"hey"
的藏宝图扔掉(但请注意,它根本不会修改s2,它仍然指向"hey"
藏宝图),并将其替换为导致"heyworld"
。
您最终将s7
更改为无处可去的空白藏宝图,然后由于s8不存在而编写了编译器错误。
在代码的这一点上,让我们看看如何仍然可以找到7种宝藏:
“嘿”-是的,通过s3和s4。仍然指向它。还有更多的意义。他们永远是“合适的”;您所要做的就是运行此主方法,该方法可以随时发生。从字面意义上写入Java文件的字符串不会消失。
“家伙”-通过s6。
“ guYs”-似乎根本找不到,但正如我所说,字符串文字永远不会消失。
副本“家伙”:仍然通过s5。
“ heyworld”-是的,s1指向它。
副本“嘿”:不,根本找不到。这个宝藏是“无法到达的”。
那么,从此基础上,嘿副本现在可以被垃圾回收了,什么都没有。
这7张藏宝图 不是可收集的实体;这些东西存在于堆栈中,并在方法退出时立即消失而无需花费任何费用。
局部变量在堆栈上的工作方式有点奇怪:在类级别,它们被转换为未命名的插槽。细节很复杂,但是只要说出某个地方某个插槽中似乎仍然存在未被引用的东西就足够了。您无法确定该方法是否真正退出,这时所有本地变量(在本例中均为宝藏图)将立即消失。
此外,实际上,垃圾收集要等到以后才开始。未提及的宝藏将被长时间困在沙子里。处理它们的最快方法是将它们留在沙子里。只要海滩足够大,就没有必要清理海滩。 GC的主题要复杂得多,但要快速上一课:直到很久以后才会发生,这很好。
答案 1 :(得分:-1)
它是这样的。
使用new
运算符创建的每个字符串都将从堆空间获取内存。所以new String("a") == new String("a")
是false
。
没有new
运算符的文学在字符串池中占有一席之地。所以"a" == "a"
是true
。
使用您的代码,我会说s1,s2,s5,s7已准备好用于GC。 s3,s4,s6被声明为文字,因此它们存储在字符串池中。