intern()在Java 6和Java 7中performance不同

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"); } } } 

此代码在Java 6和Java 7中产生不同的输出。在Java 6中, s1==s2条件返回false而在Java 7中, s1==s2返回true 。 为什么?

为什么这个程序在Java 6和Java 7中产生不同的输出?

看来,JDK7实习生的方式与以前不同。
我使用build 1.7.0-b147testing了它,得到了“两者相等”,但是当执行它(相同的字节码)和1,6.0_24时,我没有收到消息。
它还取决于String b2 =...行位于源代码中的位置。 以下代码也不会输出消息:

 class Test { public static void main(String... args) { String s1 = "Good"; s1 = s1 + "morning"; String s2 = "Goodmorning"; System.out.println(s1.intern()); //just changed here s1.intern() and the if condition runs true if(s1 == s2) { System.out.println("both are equal"); } //now it works. } } 

在没有在其string池中findstring之后,似乎是intern ,将实际的实例s1插入到池中。 当s2被创build时,JVM正在使用该池,所以它获得与s1相同的引用。 另一方面,如果首先创build了s2,则该引用被存储到池中。
这可能是因为从Java堆的永久生成中移除了被删除的string。

在这里find: 重要的RFE在JDK 7中解决

在JDK 7中,internedstring不再分配在Java堆的永久生成中,而是分配到Java堆的主要部分(称为年轻人和老一代),以及由应用程序创build的其他对象。 这种改变将导致更多的数据驻留在主Java堆中,永久代中的数据更less,因此可能需要调整堆大小。 由于这种变化,大多数应用程序在堆使用中只会看到相对较小的差异,但是加载很多类或大量使用String.intern()方法的较大应用程序将会看到更显着的差异。

不知道这是一个错误,从哪个版本… JLS 3.10.5状态

显式实施计算string的结果与具有相同内容的任何预先存在的文字string是相同的string。

所以问题是如何解释,编译时间或执行时间:预先存在或不存在?
我更喜欢它在7之前实施的方式。

我们来从示例中省略不必要的细节:

 class Test { public static void main(String... args) { String s1 = "Good"; s1 = s1 + "morning"; System.out.println(s1 == s1.intern()); // Prints true for jdk7, false - for jdk6. } } 

让我们把String#intern作为一个黑盒子。 基于几个testing用例运行,我会得出如下结论:

Java 6:
如果池包含的对象等于this ,则返回对该对象的引用,否则创build新的string(等this ),放入池中,并返回对创build的实例的引用。

Java 7:
如果池包含等于this对象,则返回对该对象的引用,否则将其放到池中,并返回this

Java 6和Java 7都没有打破方法的契约 。

看来,新的实习方法行为是这个bug的修复的结果: http : //bugs.sun.com/bugdatabase/view_bug.do?bug_id=6962931 。

==比较参考。 intern方法确保具有相同值的string具有相同的引用。

String.intern方法的javadoc解释:

公共stringintern()

返回string对象的规范表示forms。

最初为空的string池由String类私有地维护。

当调用intern方法时,如果池已经包含一个与equals(Object)方法确定的String对象相等的string,则返回该string。 否则,将此String对象添加到池中,并返回对此String对象的引用。

因此,对于任何两个strings和t,当且仅当s.equals(t)为真时,s.intern()== t.intern()才为真。

所有文字string和string值的常量expression式都被禁用。 string文字在Java语言规范的§3.10.5中定义

返回:与此string具有相同内容的string,但保证来自唯一string池。

因此,如果没有实习,编译器会查看Java代码中的常量,并从中build立常量池。 有一个由String类维护的不同的池,并且interning检查传入的string对池,并确保引用是唯一的(所以==将工作)。

在jdk6中: String s1="Good"; 在常量池中创build一个String对象“Good”。

s1=s1+"morning"; 在常量池中创build另一个String对象“morning”,但是这次实际上是JVM: s1=new StringBuffer().append(s1).append("morning").toString();

现在,当new运算符在堆中创build一个对象时,因此s1的引用是堆而不是常量池,并且String s2="Goodmorning"; 在常量池中创build一个string对象“Goodmorning”,其引用存储在s2

因此, if(s1==s2)条件为false。

但是在jdk7中会发生什么?

第一种情况:

在第一个代码中,实际上是在string池中添加了三个string。 1. s1 =“好”
2. s1 =“早上好”(连接后)3. s2 =“晚上好”

在做if(s1 == s2)时,对象是相同的,但引用不同,因此它是错误的。

第二种情况:

在这种情况下,您使用的是s1.intern(),这意味着如果池已经包含一个与equals(Object)方法确定的String对象相等的string,则返回该string。 否则,将此String对象添加到池中,并返回对此String对象的引用。

  1. s1 =“好”
  2. s1 =“早上好”(连接后)
  3. 对于strings2 =“早上好”,新的string不会被添加到池中,并为s2获取现有的string的引用。 因此如果(s1 == s2)返回true。

你需要使用s1.equals(s2) 。 使用==String对象比较对象引用本身。

编辑:当我运行你的第二个代码片段,我不会得到“两个都是平等的”打印出来。

编辑2:说明使用'=='时比较引用。

主要有4种比较string的方法:

  1. “==运算符”:它只是比较string对象的引用variables。 所以它可能会给你意想不到的结果,这取决于你如何创buildstring,即使用String类的构造函数,或者简单地使用双引号,因为两者都获得不同的内存(分别在堆和池中)。
  2. “equals(Object)method”:这是对象类的方法,由string类OVERLOADED。 它比较整个string和IS CASE SENSITIVE。
  3. “equalsIgnoreCase(String)方法”:这是string类的方法,比较整个string,并且不是CASE SENSITIVE。
  4. “比较(string)方法”:逐字符比较两个string,并返回它们的差值,如果返回值为0,则表示string相等。

每当你比较两个string之间,不要使用==和使用eqauls eqauls()因为你比较对象而不是引用:

 string1.equals(string2); 

结果代码依赖运行时:

 class Test { public static void main(String... args) { String s1 = "Good"; s1 = s1 + "morning"; System.out.println(s1 == s1.intern()); // Prints true for jdk7, false - for jdk6. } } 

如果你这样写:

 class Test { public static void main(String... args) { String s = "GoodMorning"; String s1 = "Good"; s1 = s1 + "morning"; System.out.println(s1 == s1.intern()); // Prints false for both jdk7 and jdk6. } } 

原因是'ldc#N'(从常量池加载string)和String.intern()都将在热点JVM中使用StringTable。 有关详细信息,我写了一篇英文文章: http : //aprilsoft.cn/blog/post/307.html