分享

jdk7中string.intern()方法改变

 hh3755 2014-07-21
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");
   }
  }
}

This code produces different outputs in Java 6 and Java 7. In Java 6 the s1==s2 condition returns false and in Java 7 the s1==s2 returns true. Why?

Why does this program produces different output in Java 6 and Java 7?

share|improve this question
2  
With which Java implementation does merely calling intern() on the value of a local String variable (and not assigning the return value back to the local variable) magically make the variable's value compare equal to a literal??? –  Henning Makholm Aug 15 '11 at 13:21
1  
@Mohammad Faisal Which JVM are you running? –  nfechner Aug 15 '11 at 13:31
5  
This question is asking about reference equality, not == vs. .equals(). –  Bill the Lizard? Aug 15 '11 at 14:45
1  
@Faisal, isn't the Carlos's answer that is explaining (or suggesting) the behavioural change between java 6 and java 7? Nathan's answer providing great info though. –  Reddy Aug 23 '11 at 15:55
1  
@Faisal, My point is even though Nathan explains the intern and string pool he didn't explain why there is different behaviour in java6 and 7. But Carlos's answer atleast giving pointer to a change made by Oracle in JDK which might be causing this. –  Reddy Aug 24 '11 at 10:10
show 10 more comments

9 Answers

up vote 24 down vote accepted

It seems that JDK7 process intern in a different way as before.
I tested it with build 1.7.0-b147 and got "both are equal", but when executing it (same bytecode) with 1,6.0_24 I do not get the message.
It also depends where the String b2 =... line is located in the source code. The following code also does not output the message:

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.
   }
}

it seems like intern after not finding the String in its pool of strings, inserts the actual instance s1 into the pool. The JVM is using that pool when s2 is created, so it gets the same reference as s1 back. On the other side, if s2 is created first, that reference is stored into the pool.
This can be a result of moving the interned Strings out from the permanent generation of the Java heap.

Found here: Important RFEs Addressed in JDK 7

In JDK 7, interned strings are no longer allocated in the permanent generation of the Java heap, but are instead allocated in the main part of the Java heap (known as the young and old generations), along with the other objects created by the application. This change will result in more data residing in the main Java heap, and less data in the permanent generation, and thus may require heap sizes to be adjusted. Most applications will see only relatively small differences in heap usage due to this change, but larger applications that load many classes or make heavy use of the String.intern() method will see more significant differences.

Not sure if that is a bug and from which version... The JLS 3.10.5 states

The result of explicitly interning a computed string is the same string as any pre-existing literal string with the same contents.

so the question is how pre-existing is interpreted, compile-time or execute-time: is "Goodmorning" pre-existing or not?
I prefer the way it WAS implemented before 7...

share|improve this answer
    
Should that be considered as bug? –  Reddy Aug 23 '11 at 15:56
    
@Reddy - not sure, seams that it is not specified exactly how it should be... The documentation of intern states that "this String" is stored and returned if it is not already in the pool, but I found no definition when literals should be saved into the pool. –  Carlos Heuberger Aug 23 '11 at 16:49
add comment

Let's omit unnecessary details from the example:

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.
    }
}

Let's consider String#intern as a black box. Based on a few test cases run, I would conclude that implementation is as following:

Java 6:
if the pool contains object equals to this, then return reference to that object, else create new string (equal to this), put to the pool, and return reference to that created instance.

Java 7:
if the pool contains object equals to this, then return reference to that object, else put this to the pool, and return this.

Neither Java 6 nor Java 7 breaks the contract of the method.

It seems that new intern method behavior was a result of the fix of this bug: http://bugs./bugdatabase/view_bug.do?bug_id=6962931.

share|improve this answer
1  
In jdk7 interning approach was modified, and now the method has a possibility put to the pool and return the passed instance directly. i'm not getting return the passed instance directly. Is this is specified by Sun or Oracle anywhere? –  Mohammad Faisal Aug 29 '11 at 5:42
    
@Mohammad I have reformulated my answer. –  Andrey Aug 29 '11 at 10:40
    
this should be the accepted answer. concise and precise. Explains perfectly why the same code works differently in both cases –  Jonathan Feb 10 at 14:21

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多