什么是Java中的String Interning,何时应该使用它,为什么?
根据String #intern(),intern如果在String池中找到String,则该方法应该从String池返回String,否则将在String池中添加新的字符串对象并返回此String的引用.
所以我试过这个:
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
if ( s1 == s2 ){
System.out.println("s1 and s2 are same"); // 1.
}
if ( s1 == s3 ){
System.out.println("s1 and s3 are same" ); // 2.
}
Run Code Online (Sandbox Code Playgroud)
我期待s1 and s3 are same将被打印为s3被实习,并且s1 and s2 are same不会被打印.但结果是:两行都打印出来.这意味着,默认情况下,字符串常量被实现.但如果是这样,那么为什么我们需要这种intern方法呢?换句话说,我们什么时候应该使用这种方法?
我可以'some'在MSVC生成的汇编代码中看到两个文字,但只有一个有clang和gcc.这导致完全不同的代码执行结果.
static const char *A = "some";
static const char *B = "some";
void f() {
if (A == B) {
throw "Hello, string merging!";
}
}
Run Code Online (Sandbox Code Playgroud)
任何人都可以解释这些编译输出之间的差异和相似之处吗?为什么即使没有请求优化,clang/gcc也会优化某些内容?这是某种未定义的行为吗?
我还注意到,如果我将声明更改为下面显示的声明,则clang/gcc/msvc根本不会"some"在汇编代码中留下任何声明.为什么行为不同?
static const char A[] = "some";
static const char B[] = "some";
Run Code Online (Sandbox Code Playgroud) class Test {
public static void main(String...args) {
String s1 = "Good";
s1 = s1 + "morning";
System.out.println(s1.intern());
String s2 = "Goodmorning";
if (s1 == s2) {
System.out.println("both are equal");
}
}
}
Run Code Online (Sandbox Code Playgroud)
此代码在Java 6和Java 7中生成不同的输出.在Java 6中,s1==s2条件返回false并在Java 7中s1==s2返回true.为什么?
为什么这个程序在Java 6和Java 7中产生不同的输出?
我想知道特定于.Net框架的字符串实习的过程和内部.还想知道使用实习的好处以及我们应该使用字符串实习来提高性能的场景/情况.虽然我已经从Jeffery Richter的CLR书中学习实习,但我仍然感到困惑,并希望更详细地了解它.
[编辑]使用示例代码询问具体问题如下:
private void MethodA()
{
string s = "String"; // line 1 - interned literal as explained in the answer
//s.intern(); // line 2 - what would happen in line 3 if we uncomment this line, will it make any difference?
}
private bool MethodB(string compareThis)
{
if (compareThis == "String") // line 3 - will this line use interning (with and without uncommenting line 2 above)?
{
return true;
}
return false;
}
Run Code Online (Sandbox Code Playgroud) 我看到很多这样的遗留代码:
class A {
public static final String CONSTANT = "value".intern();
...
}
Run Code Online (Sandbox Code Playgroud)
我没有看到intern()的任何原因,因为在Javadoc中可以读取:"所有文字字符串和字符串值常量表达式都被实现." 是否有一些这样的意图,也许是在过去的语言修订版中?
常见的JavaScript引擎(如V8和WebKit的JavaScriptCore)是否使用字符串实习来处理JavaScript字符串?或者他们实际上在内存中保留了多个相同字符串的实例?
String文字的行为在下面的代码中非常混乱.
我可以理解第1行,第2行和第3行true,但为什么是第4行false?
当我打印两者的哈希码时,它们是相同的.
class Hello
{
public static void main(String[] args)
{
String hello = "Hello", lo = "lo";
System.out.print((Other1.hello == hello) + " "); //line 1
System.out.print((Other1.hello == "Hello") + " "); //line 2
System.out.print((hello == ("Hel"+"lo")) + " "); //line 3
System.out.print((hello == ("Hel"+lo)) + " "); //line 4
System.out.println(hello == ("Hel"+lo).intern()); //line 5
System.out.println(("Hel"+lo).hashCode()); //hashcode is 69609650 (machine depedent)
System.out.println("Hello".hashCode()); //hashcode is same WHY ??.
}
}
class Other1 { static String hello …Run Code Online (Sandbox Code Playgroud) 我已经看到很多原始的例子描述了String intern()的工作方式,但我还没有看到一个可以从中受益的真实用例.
我能想到的唯一情况是拥有一个接收大量请求的Web服务,由于僵化的架构,每个请求都非常相似.通过intern()在这种情况下使用请求字段名称,可以显着减少内存消耗.
任何人都可以提供在生产环境中使用intern()并取得巨大成功的示例吗?也许是一个流行的开源产品中的一个例子?
编辑:我指的是手动实习,而不是字符串文字的保证实习等.
我不久前正在谈论字符串和各种语言,并且出现了字符串实习的主题.显然,Java和.NET框架会自动执行所有字符串以及多种脚本语言.从理论上讲,因为你不相同的字符串的多个副本,最终可以节省内存,这样可以节省时间,因为字符串相等比较是一个简单的指针比较,而不是一个O(N)通过串的每个字符运行.
但是我越是想到它,我越是怀疑这个概念的好处.在我看来,优势主要是理论上的:
这只是我思考实现细节的结果.有没有我错过的东西?在一般情况下,字符串实习是否实际上提供了任何显着的好处?
编辑2:好吧,显然我是在错误的前提下操作的.我正在谈话的人从未指出字符串实习对于新创建的字符串是可选的,事实上给人的印象是相反的情况是正确的.感谢Jon直接解决问题.另一个接受他的答案.
string-interning ×10
java ×7
string ×7
.net ×2
c# ×1
c++ ×1
java-6 ×1
java-7 ×1
javascript ×1
performance ×1
permgen ×1
python ×1
ruby ×1
v8 ×1
webkit ×1