[英]Why the string 'java' cann't be added to 'String Pool'
The following code confuses me, could anyone explain why the two tests behave differently? 以下代码使我感到困惑,有人可以解释为什么两个测试的行为不同吗? Why does the String comparison in the first test return
false
while the comparison in the second test returns true
? 为什么第一个测试中的String比较返回
false
而第二个测试中的比较返回true
?
public class Student {
/**
* Why the string "java" doesn't added to the 'String Pool' by intern() method ?
*/
@Test
public void test1() {
String str1 = new String("ja") + new String("va");
str1.intern();
String str2 = "java";
// Result:false
System.out.println("Result:" + (str1 == str2));
}
/**
* Any other strings will be added to 'String Pool' as expected after intern() is invoked.
*/
@Test
public void test2() {
String str1 = new String("ja1") + new String("va");
str1.intern();
String str2 = "ja1va";
// Result:true
System.out.println("Result:" + (str1 == str2));
}
You're basically checking whether a string was already in the string pool. 您基本上是在检查字符串池中是否已经有字符串。 The string "java" isn't added to the pool by calling
intern
in your first piece of code because it's already in the string pool . 字符串“ java”不会通过在您的第一段代码中调用
intern
来添加到池中, 因为它已经在字符串池中 。 In each method, your code: 在每种方法中,您的代码:
intern
on the newly created string (but ignores the result; almost always a bad idea, and you can detect the existence of a previous value in the string pool easily by using the return value) intern
(但是忽略结果;几乎总是一个坏主意,并且您可以使用返回值轻松地检测到字符串池中先前值的存在) Now the call to intern
will add the target string to the pool if it doesn't already exist, so your comparison will return true if and only if the new string value was not previously in the string pool. 现在,对
intern
的调用将把目标字符串添加到该池中(如果该目标字符串尚不存在),因此,当且仅当新字符串值先前不在字符串池中时,您的比较才会返回true。 This is equivalent to testing whether intern
returns a different reference to the target of the call. 这等效于测试
intern
是否返回对调用目标的不同引用。
For any given string reference, there are three possibilities: 对于任何给定的字符串引用,都有三种可能性:
intern()
will return the existing reference. intern()
将返回现有引用。 What you're seeing is the result of other code putting things in the string pool - quite possibly as part of loading classes. 您看到的是其他代码将内容放入字符串池的结果-很可能是加载类的一部分。 Here's an example to demonstrate that:
这是一个示例来证明这一点:
public class Test {
public static void main(String... args) {
checkInterned("ja", "va");
checkInterned("ja", "va.lang");
checkInterned("ja", "va.other");
checkInterned("Int", "eger");
checkInterned("abc", "def");
checkInterned("Te", "st");
checkInterned("Te", "st2");
checkInterned("check", "Interned");
checkInterned("check", "Interned2");
}
public static void checkInterned(String start, String end) {
String x = start + end;
String y = x.intern();
System.out.println(x + " was interned already? " + (x != y));
}
}
Output: 输出:
java was interned already? true
java.lang was interned already? true
java.other was interned already? false
Integer was interned already? true
abcdef was interned already? false
Test was interned already? true
Test2 was interned already? false
checkInterned was interned already? true
checkInterned2 was interned already? false
So the interned values are: 因此,中间值是:
java
java.lang
Integer
Test
checkInterned
They're all names that would naturally come up when loading classes (including the one being run). 它们都是在加载类(包括正在运行的类)时自然会出现的名称。
I suspect that "java" is only a special case here in that there may well be lots of code within the JRE that checks whether a string starts with "java" as a reserved name. 我怀疑“ java”在这里只是一种特殊情况,因为JRE中可能有很多代码检查字符串是否以“ java”作为保留名开头。
This doesn't indicate anything about "java" being a keyword though - it's just "a string that's already in the string pool". 但这并不表示“ java”是关键字,它只是“字符串池中已存在的字符串”。 You don't need to treat it any differently.
您无需区别对待。
The first thing to realize is that str1.intern()
doesn't change the str1
reference. 首先要意识到的是
str1.intern()
不会更改str1
引用。 It returns the interned reference. 它返回被引用的引用。 So if you wanted
str1
to now be that reference, you'd have to do: 因此,如果您希望
str1
现在成为该引用,则必须执行以下操作:
str1 = str1.intern();
So, why the difference? 那么,为什么会有所不同呢? In a nutshell, because the JVM already has a string
"java"
in its thread pool, because of various internals. 简而言之,由于各种内部因素,JVM在其线程池中已经有一个字符串
"java"
。
In the first example, str1
starts off as a newly instantiated String (as I think you understand). 在第一个示例中,
str1
以新实例化的String开头(据我认为您理解)。 You then call str1.intern()
, which returns the interned reference of a pre-existing String "java", but you don't do anything with that reference. 然后,您调用
str1.intern()
,它返回预先存在的String“ java”的内部引用,但是您对该引用不执行任何操作。 When you then compare str1 == "java"
, you're comparing the reference to the newly instantiated object with the reference to the interned object, and get false. 然后,当您比较
str1 == "java"
,您正在将对新实例化对象的引用与对被隔离对象的引用进行比较,并得到false。
In the second example, "ja1va"
does not exist in the string pool to start off. 在第二个示例中,字符串池中不存在
"ja1va"
。 When you call str1.intern()
, that method puts "ja1va" into the pool, with its current reference (that is, str1
) as the canonical reference. 当您调用
str1.intern()
,该方法将“ ja1va”放入池中,并将其当前引用(即str1
)作为规范引用。 When you subsequently refer to the "ja1va"
literal string, the JVM looks to see whether it's already in the pool, sees that it is, and uses it. 当您随后引用
"ja1va"
文字字符串时,JVM会查看它是否已经在池中,看到它并在使用它。 Thus, you get true. 这样,您就可以实现。
In other words, in the first case, you're creating a new String object and then not actually grabbing its interned equivalent. 换句话说,在第一种情况下,您正在创建一个新的String对象,然后实际上没有抓住它的等效对象。 In the second case, you're creating a new String object, defining that as the interned reference, and then reloading it via a string literal.
在第二种情况下,您将创建一个新的String对象,将其定义为内部引用,然后通过字符串文字重新加载它。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.