考虑:
String s1 = new StringBuilder("Cattie").append(" & Doggie").toString();
System.out.println(s1.intern() == s1); // true why?
System.out.println(s1 == "Cattie & Doggie"); // true another why?
String s2 = new StringBuilder("ja").append("va").toString();
System.out.println(s2.intern() == s2); // false
String s3 = new String("Cattie & Doggie");
System.out.println(s3.intern() == s3); // false
System.out.println(s3 == "Cattie & Doggie"); // false
我对于使用String.intern()
的返回值会有不同结果感到困惑,文档中写到:
当调用 intern 方法时,如果字符串池已经包含一个与此 String 对象内容相等的字符串(由 equals(Object) 方法确定),则返回池中的字符串。否则,将此 String 对象添加到池中,并返回对此 String 对象的引用。
尤其是在进行以下两个测试之后:
assertFalse("new String() should create a new instance", new String("jav") == "jav");
assertFalse("new StringBuilder() should create a new instance",
new StringBuilder("jav").toString() == "jav");
我曾经读过一篇帖子,讲了一些在其他所有内容之前被国际化的 特殊字符串
,但现在有点模糊了。
如果有一些 预先国际化
的字符串,是否有办法获取它们的列表?我只是好奇它们可能是什么。
更新
多亏了@Eran和@Slaw的帮助,现在我终于能够解释刚才发生的事情了。
true
true
false
false
false
s1.intern()
将当前对象的引用放入池中并返回自己,因为"Cattie & Doggie"
不存在于池中,所以s1.intern() == s1
;"Cattie & Doggie"
现在已经在池中了,所以字符串字面值"Cattie & Doggie"
将使用池中的引用,实际上就是s1
,因此我们再次得到true
;new StringBuilder().toString()
将创建一个新实例,而"java"
已经在池中,当调用s2.intern()
时,将返回池中的引用,因此s2.intern() != s2
,我们得到false
;new String()
也将返回一个新实例,但当尝试调用s3.intern()
时,它将返回池中先前存储的引用,实际上是s1
,因此s3.intern() != s3
,我们得到false
;- 如#2所讨论的,字符串字面值
"Cattie & Doggie"
将返回已存储在池中的引用(实际上是s1
),因此s3 != "Cattie & Doggie"
,我们再次得到false
。
感谢@Sunny提供了一个获取所有interned
字符串的技巧。
s1.intern() == s1
已经成立(因为s1.intern()
将s1
引用的实例添加到了池中),所以没有必要将s1.intern()
赋值给s1
。 - ErangetMethod("main", String[].class)
,因此“预先内部化”字符串"main"
。不同的启动器,例如通过 JNI 调用主方法的本地启动器将会有不同的行为。同样,命令行选项的处理方式也可能不同,因此对“预先内部化”的字符串列表产生不同的影响。 - Holger