简体   繁体   中英

String.intern() how to work

package com.zhb.jvm;

/**
 * 
 * @author zhb
 *
 */
public class RuntimeConstantPoolOOM {
    public static void main(String[] args){

        String str1 = "abc";
        System.out.println(str1.intern() == str1);    //true
        String str2 = new String("abcd");
        System.out.println(str2.intern() == str2);    //false

        String str3 =new StringBuilder("math").append("analyze").toString();
        System.out.println(str3.intern() == str3);    //true

        String str4 =new StringBuilder("computer").append("software").toString();
        System.out.println(str4.intern() == str4);    //true

        String str5 =new StringBuilder("jav").append("a").toString();
        System.out.println(str5.intern() == str5);    //false
    }

}

First of all,we can know the definiton of the intern() method. Definition for intern : When the intern method is invoked, if the pool already contains a string equal to thisString object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, thisString object is added to the pool and a reference to this String object is returned.

str1.intern == str1 is true. this is easy to understand. str2.intern() == str2 this is also easy to understand by the definition of the method. But why str3.intern() == str3 is true.in fact,I think it is false by the definition. There is a opposite thing that str5.intern() == str5 is false. I run the command in the terminal java -version java version "1.7.0_40" Java(TM) SE Runtime Environment (build 1.7.0_40-b43) Java HotSpot(TM) 64-Bit Server VM (build 24.0-b56, mixed mode)

I want to acquire the correct answer.thank you very much!

why str3.intern() == str3 is true

Because, as you said:

Otherwise, thisString object is added to the pool and a reference to this String object is returned.

You're in that case. The pool doesn't contain str3 (ie "mathanalyze") yet. So str3 is added to the pool and returned.

For str5, you're in the other case:

if the pool already contains a string equal to thisString object as determined by the equals(Object) method, then the string from the pool is returned

So, the pool already contains the string "java" when your code is executed, which is not surprising since java is, for example, the name of the top-level package of all the standard classes, and also the name of the executable used to launch the JVM. There is a huge chance that the literal string "java" is used in the code that bootstraps the application and loads classes before executing your main method.

The way I see it, I would say that the String "java" is by default in the pool. Indeed, when you call intern() on str3 , this word is not yet in the pool so it is added and the reference returned is str3 (no new object created), so the test gives true. At the contrary, "java" is already in the pool so it returns the reference of the object in the pool, which is different from the reference of str5 .

Note that you will observe the same behaviour not only with "java" but also with all the single characters.

The test foo.intern() == foo is a way of measuring whether or not foo was already in the pool before intern() was called. So str3.intern() == str3 means that str3 was not already in the pool. That's all.

There is probably a constant string "java" somewhere in the runtime that was loaded into the pool before your copy, which is why str5.intern() != str5 .

Here are the most obvious cases I found by grepping the OpenJDK 8 source code:

./com/sun/beans/decoder/DocumentHandler.java:        setElementHandler("java", JavaElementHandler.class); // NON-NLS: the element name
./com/sun/tools/example/debug/gui/JDBMenuBar.java:        JDBFileFilter filter = new JDBFileFilter("java", "Java source code");
./com/sun/tools/jdi/SunCommandLineLauncher.java:                "java",
./sun/launcher/LauncherHelper.java:                (progname == null) ? "java" : progname ));
./sun/rmi/server/Activation.java:                        File.separator + "bin" + File.separator + "java";
./sun/rmi/server/Activation.java:                    command[0] = "java";

As I understand there might be any runtime string "java" , which causes this issue.

    String str5 =new StringBuilder("jav").append("a").toString();
    System.out.println(str5.intern() == str5);    //false

These above two statements are only false , except any other string you want to form its passing with true .

Intern () as per Java specification.

This returns a canonical representation for the string object. A pool of strings, initially empty, is maintained privately by the class String. When the intern method is invoked, if the pool already contains a string equal to this String object as determined by the equals(Object) method, then the string from the pool is returned. Otherwise, this String object is added to the pool and a reference to this String object is returned. It follows that for any two strings s and t, s.intern() == t.intern() is true if and only if s.equals(t) is true.

All literal strings and string-valued constant expressions are interned. String literals are defined in section 3.10.5 of the The Java™ Language Specification.

Returns : a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

Hope it will help you.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM