首先要做的事情:你有变量,比如's1',这些是指针(在java中,'references')。它们就像一张藏宝图:它们本身并不是宝藏,它们只是指明了宝藏所在的方向。
在这个例子中,变量是藏宝图,字符串是宝藏。
上面的例子总共只有7个宝物:
“hey”、“guys”、“guYs”、“world”——这 4 个宝藏是在你的类加载时创建的,因为它们实际上就在你的源代码中。 guy 和 guYs 显然是不同的字符串。
第 5 个宝藏是用 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 指向它。
副本“嘿”:不,根本找不到。这个宝藏是“无法到达的”。
那么,hey-copy 现在是可垃圾回收的,没有别的了。
7 个宝藏地图 不是可收藏的实体;这些东西存在于堆栈中,并且会在方法退出的那一刻立即消失。
局部变量在堆栈上的工作方式有点奇怪:在类级别它们被转换为未命名的槽。细节很复杂,但可以说在某个位置的插槽中可能仍然存在看似未引用的事物。在方法真正退出之前,您无法确定,此时所有本地变量(在本例中都是藏宝图)立即消失。
此外,在实践中,垃圾收集要等到很久以后才会开始。没有参考的宝物会被长期卡在沙子里。处理它们的最快方法是将它们留在沙子里。只要海滩足够大,就没有必要清理海滩。 GC 的主题要复杂得多,但作为一个快速的教训:它不会在很久以后发生,这很好。