Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why String.intern() behave differently in Oracle JDK 1.7?

Tags:

java

string

Here is a java snippet:

public class TestIntern {
    public static void main(String[] argvs){
        String s1 = new StringBuilder("ja").append("va").toString();
        String s2 = new StringBuilder("go").append("lang").toString();
        System.out.println(s1 == s1.intern());
        System.out.println(s2 == s2.intern());
    }
}

And It behave different according to different JDKs

in Oracle JDK 1.7 output is:

false
true

in OpenJDK 1.6 output is also:

false
true

but in Oracle JDK 1.6 output is:

false
false

as the JavaDoc for this String#intern method indicates

 * When the intern method is invoked, if the pool already contains a
 * string equal to this <code>String</code> object as determined by
 * the {@link #equals(Object)} method, then the string from the pool is
 * returned. Otherwise, this <code>String</code> object is added to the
 * pool and a reference to this <code>String</code> object is returned.
                           ~~~~
                             And what does *this* here mean? the string object
                             in the heap or in the string pool? if it returns 
                             object in the heap the out put should be:

                             true
                             true
                             otherwise should *always* be:

                             false
                             false
                             Am I right?

the output:

true
true

should be expected, but neither three JDKs produce this. and Why Oracle JDK1.6 gives:

false
false

as a result?

I think in OracleJDK 1.7 and openJDK 1.6 there must be some reserved string in the string pool, and what are they? is there a document specify all the reserved strings? Really confused.

like image 440
armnotstrong Avatar asked Jan 07 '15 04:01

armnotstrong


People also ask

What does string intern () method do?

The method intern() creates an exact copy of a String object in the heap memory and stores it in the String constant pool. Note that, if another String with the same contents exists in the String constant pool, then a new object won't be created and the new reference will point to the other String.

What is String intern () When and why should it be used?

String Interning is a method of storing only one copy of each distinct String Value, which must be immutable. By applying String. intern() on a couple of strings will ensure that all strings having the same contents share the same memory.

What is the use of intern () in Java?

The Java String intern() method returns a canonical representation of the string object. Here, string is an object of the String class.

Does Java automatically intern strings?

When you assigned a literal to string variable it will automatically be interned. This means the string object will be added to the java string pool automatically. In contrast, when you create a string using new operator you have applied intern() method to add its copy to the java string pool.


2 Answers

Whether or not s1.intern() returns s1 or some other String object depends on what it finds in the interned strings pool. If there's already some other String object in the pool, intern() will return that other object; otherwise it will put the String object referenced by s1 into the pool and return that same object.

The issue is not the that different Java versions behave differently, it is that the pools happened to contain different things when you ran your tests. I don't find it particularly surprising that the pools in Oracle JDK 1.7 and openJDK 1.6 happened to already contain the string "java" but not the string "golang".

like image 86
Ted Hopp Avatar answered Sep 21 '22 01:09

Ted Hopp


Finally, I think I figured out all the confusions in this issue, and should make a summary.

This is a complementarity answer with @Ted answer, in his Post. He point out that it is what the program finds in the string pool that affect the result of s1 == s1.intern() returns. It perfectly explained the behavior of Oracle JDK 1.7 and the OpenJDK, but not the weird behavior of Oracle JDK 1.6, which will always return false,regardless of whatever s1 is.

I think why Oracle JDK 1.6 always return false is because of this internal string pool was in the permanent generation but was transferred to heap in JDK 1.7. So in JDK 1.6 string object on the heap and in the permanent generation will never be the same object.

To Prove this, I write a java program and run it under Oracle JDK 1.6

import java.io.*;

public class TestIntern {
    public static void main(String[] argvs){
       String s1 = null; // string inputed
       String s2 = null; // string retrieved by string.intern() in this loop
       String s3 = null; // string retrieved by string.intern() in last loop
        while (true){
            System.out.println("Enter the string");
            BufferedReader br = new BufferedReader(
                                     new InputStreamReader(System.in));

            try {
                s1 = br.readLine();
            }catch (IOException ex){
                System.out.println("IOException caught, just exit");
                System.exit(1);
            }

            s3 = s2;          //<- s3 is referring to  the string obj
                              //which retrieved from pool by last exec of loop

            s2 = s1.intern(); //<- s2 now referring to the string 
                              //obj retrieved from the string pool

            // is s1 == s2 ? // this loop
            if (s1 == s2){
                System.out.println("s1 == s2 they are same string obj");

            }else{
                System.out.println("s1 != s2 they are NOT same string obj");
            }

            // is s2 == s3 ? compared from this loop retrieved(s2) 
            //                               and last loop retrieved(s3)
            if(s2 == s3){
                System.out.println("s2 == s3 they are same string obj");
            }else{
                System.out.println("s2 != s3 they are NOT same string obj");
            }
        }
    }
}

We run this infinite loop function twice to figure out whether s2 and s3 is the same when we use the same string from stdin as input.

Apparently, when we input aaa twice to the loop, s2 and s3 referred to the same string:

-> ~/Downloads/jdk1.6.0_45/bin/java TestIntern 
Enter the string
aaa
s1 != s2 they are NOT same string obj
s2 != s3 they are NOT same string obj
Enter the string
aaa
s1 != s2 they are NOT same string obj
s2 == s3 they are same string obj
Enter the string

This means, string.inter() did add aaa to the string pool and return the object, but rather than the string object in the heap which installed by br.readLine(), this returned object is the one in the permanent generation. they are not the same.

like image 41
armnotstrong Avatar answered Sep 21 '22 01:09

armnotstrong