Java中的字符串池是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/3801343/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is String pool in Java?
提问by Subhransu Mishra
I am confused about StringPool in Java. I came across this while reading the String chapter in Java. Please help me understand, in layman terms, what StringPool actually does.
我对 Java 中的 StringPool 感到困惑。我在阅读 Java 中的字符串章节时遇到了这个问题。请帮助我理解,通俗地说,StringPool 实际上是做什么的。
采纳答案by Nikita Rybak
This prints true
(even though we don't use equals
method: correct way to compare strings)
这会打印true
(即使我们不使用equals
方法:比较字符串的正确方法)
String s = "a" + "bc";
String t = "ab" + "c";
System.out.println(s == t);
When compiler optimizes your string literals, it sees that both s
and t
have same value and thus you need only one string object. It's safe because String
is immutable in Java.
As result, both s
and t
point to the same object and some little memory saved.
当编译器优化您的字符串文字时,它会看到s
和t
具有相同的值,因此您只需要一个字符串对象。它是安全的,因为String
在 Java 中是不可变的。
作为结果,双方s
并t
指向同一个对象,并保存一些小的内存。
Name 'string pool' comes from the idea that all already defined string are stored in some 'pool' and before creating new String
object compiler checks if such string is already defined.
名称“字符串池”来自这样一个想法,即所有已定义的字符串都存储在某个“池”中,并且在创建新String
对象之前,编译器会检查此类字符串是否已定义。
回答by MStodd
I don't think it actually does much, it looks like it's just a cache for string literals. If you have multiple Strings who's values are the same, they'll all point to the same string literal in the string pool.
我认为它实际上没有多大作用,看起来它只是字符串文字的缓存。如果您有多个值相同的字符串,它们都将指向字符串池中的相同字符串文字。
String s1 = "Arul"; //case 1
String s2 = "Arul"; //case 2
In case 1, literal s1 is created newly and kept in the pool. But in case 2, literal s2 refer the s1, it will not create new one instead.
在情况 1 中,文字 s1 是新创建的并保存在池中。但在第 2 种情况下,文字 s2 引用 s1,它不会创建新的。
if(s1 == s2) System.out.println("equal"); //Prints equal.
String n1 = new String("Arul");
String n2 = new String("Arul");
if(n1 == n2) System.out.println("equal"); //No output.
回答by cHao
When the JVM loads classes, or otherwise sees a literal string, or some code intern
s a string, it adds the string to a mostly-hidden lookup table that has one copy of each such string. If another copy is added, the runtime arranges it so that all the literals refer to the same string object. This is called "interning". If you say something like
当 JVM 加载类或以其他方式看到文字字符串或某些代码intern
sa 字符串时,它会将字符串添加到大部分隐藏的查找表中,该表具有每个此类字符串的一个副本。如果添加了另一个副本,运行时会对其进行排列,以便所有文字都引用同一个字符串对象。这称为“实习”。如果你说类似的话
String s = "test";
return (s == "test");
it'll return true
, because the first and second "test" are actually the same object. Comparing interned strings this way can be much, muchfaster than String.equals
, as there's a single reference comparison rather than a bunch of char
comparisons.
它会返回true
,因为第一个和第二个“测试”实际上是同一个对象。以这种方式比较实习字符串可能比快得多String.equals
,因为只有一个参考比较而不是一堆char
比较。
You can add a string to the pool by calling String.intern()
, which will give you back the pooled version of the string (which could be the same string you're interning, but you'd be crazy to rely on that -- you often can't be sure exactly what code has been loaded and run up til now and interned the same string). The pooled version (the string returned from intern
) will be equal to any identical literal. For example:
您可以通过调用String.intern()
将字符串添加到池中,这将返回字符串的池版本(这可能与您正在实习的字符串相同,但您会很疯狂地依赖它 - 您通常可以' t 确定到底是什么代码已经被加载并运行到现在,并插入了相同的字符串)。池化版本(从 返回的字符串intern
)将等于任何相同的文字。例如:
String s1 = "test";
String s2 = new String("test"); // "new String" guarantees a different object
System.out.println(s1 == s2); // should print "false"
s2 = s2.intern();
System.out.println(s1 == s2); // should print "true"
回答by Andreas Dolk
Let's start with a quote from the virtual machine spec:
让我们从虚拟机规范中的一句话开始:
Loading of a class or interface that contains a String literal may create a new String object (§2.4.8) to represent that literal. This may not occur if the a String object has already been created to represent a previous occurrence of that literal, or if the String.intern method has been invoked on a String object representing the same string as the literal.
加载包含字符串文字的类或接口可能会创建一个新的字符串对象(第 2.4.8 节)来表示该文字。如果已经创建了一个 String 对象来表示该文字的先前出现,或者如果已经在表示与该文字相同的字符串的 String 对象上调用了 String.intern 方法,则可能不会发生这种情况。
This may not occur- This is a hint, that there's something special about String
objects. Usually, invoking a constructor will alwayscreate a new instance of the class. This is not the case with Strings, especially when String objects are 'created' with literals. Those Strings are stored in a global store (pool) - or at least the references are kept in a pool, and whenever a new instance of an already known Strings is needed, the vm returns a reference to the object from the pool. In pseudo code, it may go like that:
这可能不会发生- 这是一个提示,String
对象有一些特殊之处。通常,调用构造函数将始终创建类的新实例。字符串不是这种情况,尤其是当字符串对象是用文字“创建”时。这些字符串存储在全局存储(池)中 - 或者至少引用保存在池中,并且每当需要已知字符串的新实例时,vm 从池中返回对对象的引用。在伪代码中,它可能是这样的:
1: a := "one"
--> if(pool[hash("one")] == null) // true
pool[hash("one") --> "one"]
return pool[hash("one")]
2: b := "one"
--> if(pool[hash("one")] == null) // false, "one" already in pool
pool[hash("one") --> "one"]
return pool[hash("one")]
So in this case, variables a
and b
hold references to the sameobject. IN this case, we have (a == b) && (a.equals(b)) == true
.
所以在这种情况下,变量a
和b
持有对同一个对象的引用。在这种情况下,我们有(a == b) && (a.equals(b)) == true
.
This is not the case if we use the constructor:
如果我们使用构造函数,则情况并非如此:
1: a := "one"
2: b := new String("one")
Again, "one"
is created on the pool but then we create a new instance from the same literal, and in this case, it leads to (a == b) && (a.equals(b)) == false
同样,"one"
在池上创建,但随后我们从相同的文字创建了一个新实例,在这种情况下,它导致(a == b) && (a.equals(b)) == false
So whydo we have a String pool? Strings and especially String literals are widely used in typical Java code. And they are immutable. And being immutable allowed to cache String to save memory and increase performance (less effort for creation, less garbage to be collected).
那么为什么我们有一个字符串池呢?字符串,尤其是字符串文字在典型的 Java 代码中被广泛使用。而且它们是不可变的。并且不可变允许缓存 String 以节省内存并提高性能(更少的创建工作,更少的垃圾收集)。
As programmers we don't have to care much about the String pool, as long as we keep in mind:
作为程序员,我们不必太在意String池,只要记住:
(a == b) && (a.equals(b))
may betrue
orfalse
(alwaysuseequals
to compare Strings)- Don't use reflection to change the backing
char[]
of a String (as you don't know who is actualling using that String)
(a == b) && (a.equals(b))
可能是true
或false
(总是用于equals
比较字符串)- 不要使用反射来更改
char[]
字符串的支持(因为您不知道谁在实际使用该字符串)