1

I read this when should we use intern method of string on string constants but still not very clear with String == compare also with intern(). I have a couple examples. Can someone help me understand this better.

String s1 = "abc";
String s2 = "abc";
String s3 = "abcabc";
String s4 = s1 + s2;

System.out.println(s3 == s4);                            // 1. why false ?
System.out.println(s3 == s4.intern());                   // 2. why true ?
System.out.println(s4 == s1 + s2);                       // 3. why false ?
System.out.println(s4 == (s1 + s2).intern());            // 4. why false ?
System.out.println(s4.intern() == (s1 + s2).intern());   // 5. why true ?
Community
  • 1
  • 1
peter
  • 8,333
  • 17
  • 71
  • 94
  • Intern inserts a certain string value in the String pool so the interned string are equal to the "litterals" refs. Theyre pointing to the same object in the pool after intern. – Yassin Hajaj Oct 24 '15 at 22:36
  • 2
    For real code: Never use the intern pool and always use `equals()`. There's almost never a good reason to intern strings manually. – chrylis -cautiouslyoptimistic- Oct 24 '15 at 22:38
  • @chrylis I agree with that, but I am just trying to understand what happens behind the scene. – peter Oct 24 '15 at 22:40

3 Answers3

3

There are quite a lot of answers here which exlain that, but let me give you another one.

A string is interned into the String literal pool only in two situations: when a class is loaded and the String was a literal or compile time constant. Otherwise only when you call .intern() on a String. Then a copy of this string is listed in the pool and returned. All other string creations will not be interned. String concatenation (+) is producing new instances as long as it is not a compile time constant expression*.

First of all: never ever use it. If you do not understand it you should not use it. Use .equals(). Interning strings for the sake of comparison might be slower than you think and unnecessarily filling the hashtable. Especially for strings with highly different content.

  1. s3 is a string literal from the constant pool and therefore interned. s4 is a expression not producing an interned constant.
  2. when you intern s4 it has the same content as s3 and is therefore the same instance.
  3. same as s4, expression not a constant
  4. if you intern s1+s2 you get the instance of s3, but s4 is still not s3
  5. if you intern s4 it is the same instance as s3

Some more questions:

System.out.println(s3 == s3.intern());       // is true
System.out.println(s4 == s4.intern());       // is false
System.out.println(s1 == "abc");             // is true
System.out.println(s1 == new String("abc")); // is false

* Compile time constants can be expressions with literals on both sides of the concatenation (like "a" + "bc") but also final String variables initialized from constants or literals:

    final String a = "a";
    final String b = "b";
    final String ab = a + b;
    final String ab2 = "a" + b;
    final String ab3 = "a" + new String("b");
    System.out.println("ab == ab2 should be true:  " + (ab == ab2));
    System.out.println("a+b == ab should be true:  " + (a+b == ab));
    System.out.println("ab == ab3 should be false: " + (ab == ab3));
eckes
  • 10,103
  • 1
  • 59
  • 71
  • 1
    *"including + operator - even with 2 literals"* This is either wrong or very imprecise. – Tom Oct 24 '15 at 22:57
  • When you create a new String instance with the concatenation operator, the result will be not automatically interned. Not even (by the compiler which could to that as an optimization) if both operands are literal strings. – eckes Oct 24 '15 at 23:01
  • 1
    As I said, this is imprecise. Since you got the code from OP you can try it yourself: `System.out.println("ab" + "c" == s1);`. And then please do some research about compile time constants, because `System.out.println(s3 == s4);` would be true if `s1` and `s2` are `final`. – Tom Oct 24 '15 at 23:04
0

One thing you have to know is, that Strings are Objects in Java. The variables s1 - s4 do not point directly to the text you stored. It is simply a pointer which says where to find the Text within your RAM.

  1. It is false because you compare the Pointers, not the actual text. The text is the same, but these two Strings are 2 completely different Objects which means they have diferent Pointers. Try printing s1 and s2 on the console and you will see.

  2. Its true, because Java does some optimizing concerning Strings. If the JVM detects, that two different Strings share the same text, they will be but in something called "String Literal Pool". Since s3 and s4 share the same text they will also sahe the same slot in the "String Literal Pool". The inter()-Method gets the reference to the String in the Literal Pool.

  3. Same as 1. You compare two pointers. Not the text-content.

  4. As far as I know added values do not get stored in the pool

  5. Same as 2. You they contain the same text so they get stored in the String Literal Pool and therefore share the same slot.

MikeVe
  • 1,062
  • 8
  • 13
  • 1
    I dont think printing s1 + s2 will give any useful insight .) The JVM does btw not detect it, its the compiler constructing classes to stuff the literals into the pool. The other way is with intern() (which is avoided). – eckes Oct 24 '15 at 22:45
  • But printing them will give him an idea of references and how they are different for every object. – MikeVe Oct 24 '15 at 22:46
  • First it is false, because they are different objects and then the JVM optimizes that? If this would really be the case, then why is *1.* wrong if the JVM optimized "that"? – Tom Oct 24 '15 at 22:46
  • 1
    No it will not, if you print a string it shows its content which is the same. You could print the [`System.idendityHashCode(s1)`](http://docs.oracle.com/javase/7/docs/api/java/lang/System.html#identityHashCode%28java.lang.Object%29), but that might be missleading. – eckes Oct 24 '15 at 22:47
  • Yes, sorry. You are right. It just works for other than String objects. – MikeVe Oct 24 '15 at 22:56
  • The JVM does optimize! 1 is just wrong because Strings are "immutable". Each time you perform a operation like "+" a new String is generated. A String which is declared like `String s = "Test"` is considered a "String literal" and therefore is stored in the pool. A String declared like `String s = s2 + s3` is considered a "String constand expression" an is not stored in the pool. Thats why 1 is false – MikeVe Oct 24 '15 at 23:06
  • *"A String declared like String s = s2 + s3 is considered a "String constand expression" an is not stored in the pool."* This is not always true. It depends on `s2` and `s3`. Please check what "compile time constants" are, it might help you here. – Tom Oct 24 '15 at 23:09
  • @Tom i am wondering in what case a string constant expression that would be stored in the pool. Can you give an example please – peter Oct 25 '15 at 14:34
0

To start off with, s1, s2, and s3 are in the intern pool when they are declared, because they are declared by a literal. s4 is not in the intern pool to start off with. This is what the intern pool might look like to start off with:

"abc" (s1, s2)
"abcabc" (s3)
  1. s4 does not match s3 because s3 is in the intern pool, but s4 is not.
  2. intern() is called on s4, so it looks in the pool for other strings equaling "abcabc" and makes them one object. Therefore, s3 and s4.intern() point to the same object.
  3. Again, intern() is not called when adding two strings, so it does not match from the intern() pool.
  4. s4 is not in the intern pool so it does not match objects with (s1 + s2).intern().
  5. These are both interned, so they both look in the intern pool and find each other.
Nathan Bierema
  • 1,813
  • 2
  • 14
  • 24
  • 1
    *"because s1 + s2 is not a string literal"* I guess you should explain that a bit better, because variables can't be literals and they are initiliazed using literals. – Tom Oct 24 '15 at 22:50