Win a copy of Murach's Java Programming this week in the Beginning Java forum!
  • Post Reply Bookmark Topic Watch Topic
  • New Topic

Strings  RSS feed

 
Lilou Laure
Ranch Hand
Posts: 36
2
  • Likes 2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

code 1 :



code 2 :



I observe something very strange in the above ! line 7 in code 1 prints false !! but why ??    
But in code 2 it prints true !      I expected it to print true in both !

 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Honestly I expected it to print true in both cases as well. And if you change "va" to "vb" (or something else) in the 1st code snippet, it prints true as expected.

So I assume the String "java" is already in the String Literal Pool (for some reason) and therefore b.intern() returns a reference to that String without having to add String "java" to the String Literal Pool.

And just out of curiosity I've tried the same with a few other keywords from the method signature:
String b="ar".concat("gs"); => true
String b="ma".concat("in"); => false
String b="pub".concat("lic"); => true

So for String "main" you'll have the same output as for String "java".
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:...I assume the String "java" is already in the String Literal Pool (for some reason) and therefore b.intern() returns a reference to that String without having to add String "java" to the String Literal Pool.

I doubt that the string "java" is already in the String Literal Pool since the API documentation for the intern() method says that the pool is initially empty.
A pool of strings, initially empty, is maintained privately by the class String.

I suspect that the reason why the code snippets return false and true is that when we call b.intern(), the only guarantee the API makes is that b.intern() will return a string from the pool. The API does not guarantee that b will refer to a string in the pool.

The API documentation for the intern() method says:
Returns:
a string that has the same contents as this string, but is guaranteed to be from a pool of unique strings.

In order to ensure that the code snippets return true and true and ensure that b refers to a string in the pool, we must add

 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Cox wrote:I doubt that the string "java" is already in the String Literal Pool since the API documentation for the intern() method says that the pool is initially empty.

I know the pool is empty, but that doesn't mean the String "java" can't be added for any reason...

Daniel Cox wrote:I suspect that the reason why the code snippets return false and true is that when we call b.intern(), the only guarantee the API makes is that b.intern() will return a string from the pool. The API does not guarantee that b will refer to a string in the pool.

From the same API you have quoted earlier:
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.
Meaning if the String "java" does not yet exist in the pool (as in the 2nd example), the String object (also refered to by b) is added to the pool and that reference is returned and assigned to c, resulting b and c having the same reference.
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:I know the pool is empty, but that doesn't mean the String "java" can't be added for any reason...

Sorry I misunderstood you 

Roel De Nijs wrote:...resulting b and c having the same reference.

Yes, b and c have the same reference in the 2nd example, but the coding is wrong which is why b and c do not have the same reference in the 1st example. The code String c=b.intern() guarantees that c refers to the string "java" in the pool but does not guarantee that b refers to the same string "java" in the pool as demonstrated by the 1st example. One way to guarantee this is b=b.intern().
 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Cox wrote:The code String c=b.intern() guarantees that c refers to the string "java" in the pool but does not guarantee that b refers to the same string "java" in the pool as demonstrated by the 1st example.

That's in fact the beauty of this question... If the String "java" was not yet in the String Literal Pool, the String "java" would be added to the String Literal Pool and that reference would be returned resulting in b and c referring to the same object (according to the javadoc of the intern() method and illustrated with the 2nd code snippet). Because another reference is returned (resulting in printing false when comparing  b and c) means the String "java" was already in the String Literal Pool.Why is "java" (and "main") already in the String Literal Pool
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:Why is "java" (and "main") already in the String Literal Pool

Because as you said earlier, when intern() runs
the string "java" will be added to the pool (if it is not already there).

Roel De Nijs wrote:If the String "java" was not yet in the String Literal Pool, the String "java" would be added to the String Literal Pool and that reference would be returned resulting in b and c referring to the same object (according to the javadoc of the intern() method and illustrated with the 2nd code snippet).

I think that the statement "resulting in b and c referring to the same object" is wrong. When intern() runs
the API says that the string "java" will be added to the pool (if it is not already there). The API then says that a reference to the string in the pool will be returned; implying that c will refer to the string "java" in the pool. The API does not guarantee that b will refer to the string "java" in the pool.
 
Tobias Bachert
Ranch Hand
Posts: 83
18
  • Likes 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
The JVM loads quite a few classes on startup - as the strings are already in the pool at least one of them has to contain code that contains the literal and has to be executed prior the main method is invoked.

A short scan of the loaded classes for a Java9 version (obtained by using -verbose:class) shows, that two of the loaded classes contain the literals:
java.lang.VersionProps - contains "java", reason for "java" being interned (static field initializer contains the literal, class is initialized in init phase 1)
sun.launcher.LauncherHelper - contains "java" and "main", reason for "main" being interned (method for the main-method validation contains the literal)

The used code to scan the classes for the literals:
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's okay to peer into the internal workings of the JVM but it's best to abide by the guarantees imposed by the Java API.
 
Lilou Laure
Ranch Hand
Posts: 36
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
hmmm.....

this is quite interesting !   
 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Cox wrote:I think that the statement "resulting in b and c referring to the same object" is wrong.

No, it's not! Based on the javadoc of the intern() method that's guaranteed if and only if the String object was not yet in the String Literal Pool. And the reason why it's guaranteed is mentioned in the javadoc of the intern() method (which I've quoted in one of my previous post)Assuming String "daniel" is not yet in the String Literal Pool, this is what happens (in a simplified version). The String object is created and reference 1979 is stored in variable b. When b.intern() is invoked, the JVM checks if the String "daniel" is already in the String Literal Pool. But it's not (according to our assumption). So that means the String "daniel" will be added to the String Literal Pool (e.g. POOL[counter++] = this;) and that reference (1979) is returned (which is assigned to c). So now you have three reference variables refering to the same String object: b, c and POOL[0] (assuming no other strings were already added to the pool).

A very simplified version of the intern() method would look like this
 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Tobias Bachert wrote:The used code to scan the classes for the literals:

Great stuff Have a cow!
 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Lilou Laure wrote:this is quite interesting !

That's definitely interesting but please note that this is waaaaay beyond the scope for the OCAJP and OCPJP certification exams Have a cow for a great question!
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
@Tobias - some ranchers might be interested in making your code compile.
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:So now you have three reference variables refering to the same String object: b, c and POOL[0] (assuming no other strings were already added to the pool).

You're assuming that b.intern() implies that b will refer to a string in the pool. This is not correct.

The way to guarantee that b refers to a string in the pool is b=b.intern()

If your assumption was correct, this code will print true. It prints false because a refers to the string "jack" in the pool but b does not refer to the same string in the pool.

This code prints true because a and b refer to the string "jack" in the pool.
 
Lilou Laure
Ranch Hand
Posts: 36
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:
Lilou Laure wrote:this is quite interesting !

That's definitely interesting but please note that this is waaaaay beyond the scope for the OCAJP and OCPJP certification exams Have a cow for a great question!


woohooo !!!       

thanks roel ! 
 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Cox wrote:@Tobias - some ranchers might be interested in making your code compile.

As Tobias mentioned you'll probably need JDK9 to successfully compile his code snippet. But it would be indeed interesting to know if the used class constants are defined somewhere in the Java API or are custom defined (and if so, to which values).
 
Roel De Nijs
Sheriff
Posts: 11295
177
AngularJS Chrome Eclipse IDE Hibernate Java jQuery MySQL Database Spring Tomcat Server
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Daniel Cox wrote:
Roel De Nijs wrote:So now you have three reference variables refering to the same String object: b, c and POOL[0] (assuming no other strings were already added to the pool).

You're assuming that b.intern() implies that b will refer to a string in the pool. This is not correct.

I wonder why you only quote one sentence from a three line (on my computer) paragraph - therefore get rid of all context I've provided (which is very important here) - and tell me I am wrong

I have never said in this entire thread (nor in any other thread on this website) that any invocation of the intern() method will always result in three reference variables refering to the same String object. Never! Because that would simply be incorrect as mentioned in the javadoc of the intern() method (and also illustrated in your code snippets).

The only thing I've said: if and only if the String object is not yet present in the String Literal Pool (and this is the context you simply got rid of) and then you call the intern() method (like in the code snippet with "ja" and "ck" in the OP's 2nd code snippet), you will have three reference variables refering to the same String object: b, c and POOL[someIndex]. And that's actually guaranteed behavior (mentioned in the javadoc of the intern() method, also quoted by me somewhere in this topic).
And of course I know it's hard (if not impossible) to know if a String is already in the String Literal Pool (certainly in very large applications as many classes with String literals will be loaded to run the application), but that's completely irrelevant here. In this very simple code snippet we all know that the String object "jack" is not yet in the String Literal Pool when the intern() method is invoked.
 
Lilou Laure
Ranch Hand
Posts: 36
2
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
also thanks to roel , tobias and daniel for all the valuable answers and code snippets you all have taken time and  provided !   

 
Tobias Bachert
Ranch Hand
Posts: 83
18
  • Likes 3
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I did not post the whole code as it would have forced me to rewrite code (not something I wanted to do at ~4am :D); but the previous code should contain sufficient information to add the missing parts.
The following code requires Java9 and compiles; the same is possible with Java8 (with the corresponding classes of sun.* instead of jdk.internal.* - simply replace #getTagAt with a try-catch block, obtain the unsafe instance via reflection and change the regex to match the verbose:class output).
 
Daniel Cox
Ranch Hand
Posts: 211
9
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Roel De Nijs wrote:I wonder why you only quote one sentence from a three line (on my computer) paragraph - therefore get rid of all context I've provided (which is very important here) - and tell me I am wrong

Sorry about this. Having gone through your post in greater detail, I see your point.

@Tobias - Thanks for pointing out why "java" and "main" are already in the pool. 
 
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!