开发者

Java - tell if a String is interned?

So the question here is pretty simple: is there a way to tell if a String in Java is interned? My guess 开发者_如何学编程is no, but I'm wondering if anyone knows better.


The only way you can find out if a String is interned is to call intern() and check if it returns itself:

boolean hasBeenInternedBefore = myString.intern() == myString;

This obviously has the drawback of interning the String when it wasn't interned before.

Going partially off-topic, there's a way to do "custom" interning with an explicit pool using the Interner interface of Guava (using the implementations exposed by the Interners class). This has the advantage of being able to let the Interner itself (and thuse the pool) being garbage collected when it's no longer referenced.


There is a way to check if the particular String object was already interned, but it inserts the contents into the string pool if those contents weren't already interned. Create a new String object with the same contents, intern that, and compare to your original object:

new String(s).intern() == s

This works because of the fact that new String(s) != s. Consider each possible situation:

  1. s is interned in the string pool. new String(s) has the same contents as s, so intern() called on it will return s. The expression's result is true.
  2. s is not interned in the string pool, but another equal String object is—let's call it s2. intern() will return s2, so the expression's result is false.
  3. s is not interned in the string pool, and neither is any String equal to it. In this case, new String(s) will be interned into the string pool, which unfortunately modifies the string pool. Because this is not the same String object as s, the expression's result is false.

Thus the above expression will correctly test if s is interned in the string pool or not. The following test demonstrates this:

public static void main(String[] args) {
    String interned = new String(new char[] { 'i', 'n', 't' }).intern();
    String notInterned = new String(new char[] { 'n', 'o', 't' });
    System.out.println("Case 1: " + wasInterned(interned));
    System.out.println("Case 2: " + wasInterned(new String(interned)));
    System.out.println("Case 3: " + wasInterned(notInterned));
}

public static boolean wasInterned(String s) {
    return new String(s).intern() == s;
}

When run, the output is:

 Case 1: true
 Case 2: false
 Case 3: false


We can't look inside the repository of interned strings and can't get a set of all interned Strings.

Testing, if a given String has been interned already creates a nice dilemma (a common problem with measurements by the way): the measuring itself may affect the repository of interned Strings ;)

To test, if a repository contains a given String, we need to compare that String to (worst case) all Strings in that repository - with the risk, that JVM interns this reference String before we start comparing... which would return a true although the String wasn't interned before the test ;)

But apart from this, I don't see any practical use in knowing if the virtual machine has interned a String already or not. Interning is cheap enough, just intern it if needed. (And if there was a practical use, the String class would offer a native test method)


No. Generally speaking, you shouldn't need to check - just intern them to be sure or don't rely on interning. If you need interned or non-interned strings for testing or experimenting, you can make them:

Interned:

s = someArbitraryString.intern();

Non-interned:

s = new String(someArbitraryString);
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜