5
String a = "abc";
String b = a.substring(1);
b.intern();
String c = "bc";
System.out.println(b == c);

The question might be foolish as intern has no major usage here, still I am confused about the fact, why does b == c results true.

When

String b = a.substring(1)

is executed, String b references to object having "bc"

Does b.intern create the literal "bc" in String Constant pool, even if it does, how come b==c result in true?

Pshemo
  • 122,468
  • 25
  • 185
  • 269
Arijit Dasgupta
  • 325
  • 3
  • 14
  • 1
    Have a look by yourself at the documentation for [intern](https://docs.oracle.com/javase/8/docs/api/java/lang/String.html#intern) – x80486 Oct 28 '15 at 19:07

2 Answers2

5

Look at the doc of String#intern() method

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.

Now follow the comments

    String b = a.substring(1);  // results "bc"
    b.intern();                 // check and places "bc" in pool
    String c = "bc";            // since it is a literal already presented in pool it gets the reference of it
    System.out.println(b == c);// now b and c are pointing to same literal
Suresh Atta
  • 120,458
  • 37
  • 198
  • 307
  • Downvoter, care to explain what is the reason for it ? – Suresh Atta Oct 28 '15 at 19:14
  • Thanks for the quick reply, but doesn't String b still point to the object in memory having bc? b.intern returns the reference from String pool, but it we are not saving the reference anywhere – Arijit Dasgupta Oct 28 '15 at 19:14
  • Calling `b.intern()` does nothing to `b`, but it places a copy of the string it refers to into the string pool. The result of running this code will be `false`. The code should have `b = b.intern();`. – user207421 Oct 28 '15 at 19:14
  • Arjit and @EJP note the document line `Otherwise, this String object is added to the pool ` here this refers to `b` – Suresh Atta Oct 28 '15 at 19:17
  • @EJP Nope, creating separate copy doens't make sense since it would consume more memory (which kind of defetes purpose of String Pool). Simply test it http://ideone.com/zVu8Wl – Pshemo Oct 28 '15 at 19:17
  • 1
    @EJP `intern` returns string from pool which is `equal` to our string. If pool already has different string which is equal to one from `b` then that different string will be returned, but if pool doesn't contain such string the one from `b` will be placed in pool and then returned so `b = b.intern()` is same as `b.intern()` for this case (since `intern` will return instance which `b` holds). – Pshemo Oct 28 '15 at 19:27
  • @Pshemo, `b=b.intern()` is same as `b.intern()` solves all my doubts now. Just a question out of my curiosity, A lot of blogs speak about String inter Pools, is it same as String Literal pool? – Arijit Dasgupta Oct 28 '15 at 19:32
  • @ArijitDasgupta notice that `b=b.intern()` is same as `b.intern()` *only if there was no such string as one from `b` in pool*. If pool would contain string like `"bc"` earlier, then `b.intern()` would return string from pool, not the one from `b`. – Pshemo Oct 28 '15 at 19:34
5

String b = a.substring(1); returns string instance which contains "bc" but this instance is not part of string pool (only literals are by defaults interned, string created via new String(data) and returned from methods like substring or nextLine are not interned by default).

Now when you invoke

b.intern();

this method checks if String Pool contains string equal to one stored in b (which is "bc") and if not, it places that string there. So sine there is no string representing "bc" in pool it will place string from b there.

So now String pool contains "abc" and "bc".

Because of that when you call

String c = "bc";

string literal representing bc (which is same as in b reference) will be reused from pool which means that b and c will hold same instance.

This confirms result of b==c which returns true.

Pshemo
  • 122,468
  • 25
  • 185
  • 269
  • But String b is pointing to an object containing "bc", b.intern(); just puts the "bc" in String pool and when we execute String c = "bc" it fetches the reference from the String Pool, while String b is pointing to the object containing "bc". How does b and c contain the same reference. Please let me know where am I wrong – Arijit Dasgupta Oct 28 '15 at 19:23
  • I'm not the voter, but this *"So sine there is no string representing "bc" in pool"* sounds wrong, because `"bc"` is already in the pool, because that literal (from `String c = "bc"`) will be interned during class loading. – Tom Oct 28 '15 at 19:35
  • @Tom Notice that `String c = "bc"` is after `b.intern();` so there was no `"bc"` literal earlier. – Pshemo Oct 28 '15 at 19:37
  • It shouldn't matter much, because the compiler writes every literal into a constant pool, which when will be loaded and interned by the JVM during class loading. – Tom Oct 28 '15 at 19:38
  • @Tom Not quite. String pool is filled at runtime, can compiler doesn't produce list of literals used in class. String pool is filled with elements when literal is being first time created. – Pshemo Oct 28 '15 at 19:41
  • @Tom Maybe this will convince you: http://ideone.com/GxiasM. Notice that `foo` is creating new string which holds `"abc"` but this string is not placed in String Pool since it was created by `new` operator. Then we interned it (without changing `foo` reference) and after creating `bar` string using literal it was same instance as the one from `foo` (which `foo==bar` proves). – Pshemo Oct 28 '15 at 19:45
  • @Tom Now if we move line `String bar = "abc";` at start of this example result of `foo == bar` would be false, which means in original version of this example `String foo = new String(new char[]{'a','b','c'}); foo.intern();` places string from `foo` reference representing `"abc"` in pool earlier and `String bar = "abc";` is simply reusing it. – Pshemo Oct 28 '15 at 19:47
  • No worries I already tested that. It disturbs me, that everytime I read something about the behaviour of String literals it said: compiler files constant pool (which is correct) and JVM loads that then it load the class (which might be wrong). It seems that the JVM will intern the String _when_ it will be loaded from the constant pool the first time, which is new to me. – Tom Oct 28 '15 at 19:57
  • now I am a little confused, as per @tom if the String pool gets loaded at Class load time(which I read too in some of the articles), then we might have a totally different situation here. – Arijit Dasgupta Oct 28 '15 at 20:01
  • @Tom It is not that "compiler files constant pool". You can think of it more like that *when compiling string literals compiler adds to it (or replaces it with) code responsible for adding this literal to pool, or retrieving from pool string which is equal to one we want to create*. So compiler helps us to manage string pool, but its using happens at runtime each time JVM is using literals. – Pshemo Oct 28 '15 at 20:08
  • With "constant pool" I don't mean the String constant pool. I mean the "pool" which each class contain. And this one is filed by the compiler. But it doesn't seem to be the case that he JVM loads the whole pool and interns every String in there, when it loads the class. This is the new thing for me. Btw this is one of the posts I mean: http://stackoverflow.com/questions/3451145/when-are-java-strings-interned – Tom Oct 28 '15 at 20:14
  • As per the question in : http://stackoverflow.com/questions/3451145/when-are-java-strings-interned, Intern pools are different from String pool. Is that true? – Arijit Dasgupta Oct 28 '15 at 20:25
  • @ArijitDasgupta Actually I can't answer that question. Maybe you should create separate topic about it or ask Jon for clarification under his answer. – Pshemo Oct 28 '15 at 21:17