java之为什么 JVM 不是 "seeing"字符串池内存中的重复字符串值
可能这是重复的,但找不到我需要的解释。有人可以向我解释这一点。
如果我是对的:
String s1 = "a";
String s2 = "a";
s1 和 s2 都将指向字符串池中的相同地址,并且只有一个值为“a”的对象。
现在,如果我这样做:
String s1 = "a"; //line A
s1 = s1.concat("b"); //line B; I don't understand what's happening here in terms of references
String s2 = "ab";//line C
System.out.println(s1 == s2); //false
为什么我得到
false
?
我的看法(可能是错误的)是这样的:
after line A
-> 在字符串池中创建对象(值为
a
),由
s1
引用;
after line B
-> 在字符串池中创建值为
b
的对象(没有引用),然后在字符串池中创建值为
ab
的新对象(由现有
s1
引用)
after line C
->(这可能是我错了)由于使用
ab
(或 +)创建了具有
s1
值的现有对象(由
concat()
引用),JVM 不会重用此对象以通过引用
s2
指向,它只会创建字符串池中的新对象,值
ab
由引用
s2
指向;
我哪里错了?
请您参考如下方法:
TL;DR - 您的困惑点是字符串的 Java 内存模型,即内存的堆和字符串常量池区域。
深入研究字符串内存模型
设计动机
在 Java 中,String 可能是使用最频繁的对象。因此,Java 使用特殊的内存设计策略来维护 String 对象,将它们保存在 Heap 中,或者保存在称为 String Constant Pool 的堆的隔 ionic 集中,或者同时保存在两者中。
String Constant Pool 是 Heap 内存中的一个特殊空间,它保存着唯一 "literal value"
的 String 对象。任何时候你用它的字面值创建一个字符串时,JVM 首先检查字符串池中是否有相同值的对象,如果是,则返回对同一对象的引用,如果没有 - 新对象是分配在字符串常量池中,并且所有其他字符串文字创建一次又一次发生同样的情况。
原因,为什么拥有常量池是一个好主意,是这个短语本身的语义 - 因为它存储常量和不可变的 String 对象,正如你所看到的,当你可能创建许多 String 时,这是一个好主意具有相同文字内容的对象 - 在所有这些情况下,每次只会引用一个 "literal value"
的一个对象,并且 不会为现有的 String 文字对象创建更新的对象 。
Note, that this is only possible because, String is immutable by definition. Also, note, that a pool of strings, which initially is empty, is maintained privately by the class String.
Java 将 String 对象放在哪里?
现在这就是事情变得有趣的地方。要记住的重要一点是,每当您使用
new String()
指令创建 String 对象时,您都会强制 Java 将新对象分配到堆中;但是,如果您使用
"string literal"
创建一个 String 对象,它将在 String Constant Pool 中分配。正如我们所说,String Constant Pool 的存在主要是为了减少内存使用并提高内存中现有 String 对象的重用率。
所以,如果你会写:
String s1 = "a";
String s2 = "a";
String s3 = new String("a");
s1
中; "a"
)的对象,将返回对同一个对象的引用; s3
中。 内部字符串
如果您希望将使用
new
运算符创建的 String 对象移动到字符串常量池中,您可以调用
"your_string_text".intern();
方法,并且两个
will 之一发生:
你的代码会发生什么?
String s1 = "a";
String s2 = "a";
Both s1 and s2 will point to the same address in String pool and there will be only one object with value "a".
真的。最初,将创建字符串对象并将其放入字符串常量池中。之后,由于已经存在值为
"a"
的 String ,因此不会为
s2
创建新对象,并且存储在
s1
中的引用将类似地存储到
s2
中。
现在,让我们终于来看看你的问题:
String s1 = "a"; //allocated in the String Constant Pool
s1 = s1.concat("b"); //contact() returns a new String object, allocated in the Heap
String s2 = "ab";//"ab" still does NOT exist in the String Constant Pool, and it gets allocated there
System.out.println(s1 == s2); //returns false, because one object is in the Heap, and another is in the String Constant Pool, and as there already exists the object in the pool, with the same value, existing object will be returned by `intern()`.
但是,如果您愿意,请执行
System.out.println(s1.intern() == s2);
这将返回
true
,我希望现在你明白了 - 为什么。因为
intern()
会将通过
s1
引用的对象从 Heap 移动到 String Constant Pool。
1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。