Beware: I'm not trying to compare if the characters are equals. Because I know how to use the String.equals() method. This question is about String reference
I was studying for the OCA exam when I started to learn about the class String and it properties as immutability, etc. According to what I read or may understand about String pool is that when a string is created Java stores this object on what they call String pool and if a new string is created with the same value it is going to make reference to the string on the String pool except is the case we use the new keyword as this creates a new reference even both string contains the same value.
For example:
String a = "foo";
String b = "foo";
String c = new String("foo");
boolean ab = (a == b); // This return true
boolean ac = (a == c); // This return false
To be clear what this code is making is on the first line of code it will create the String a = "foo" and store this on the String pool, and on the second line of code it will create the String b and reference to "foo" because this already exist on the String pool. But line 3 will create a new reference of this string no matter if this already exist. Here is a little graphic example about what is happening:
The problem comes on the followings lines of code. When the string is created by concatenation does java make something different or simple == comparator have another behaviour ?
Example A:
String a = "hello" + " world!";
String b = "hello world!";
boolean compare = (a == b); // This return true
Example B:
a = "hello";
b = "hel" + "lo";
compare = (a == b); // This return true
Example C:
a = "Bye";
a += " bye!";
b = "Bye bye!";
compare = (a == b); // This return false
To watch the code running: (http://ideone.com/fdk6KL)
What is happening ?
EDIT
Fixing error on the Example B: b = 'hel' + 'lo'
Adding clarification about the problem. It's not a comparison problem cause I know the use of String.equals() the problem is on the reference on the String pool
"When the string is created by concatenation does java make something
different or simple == comparator have another behaviour?"
No it does not change its behavior, what happens is that:
When concatenating two string literals "a" + "b" the jvm joins the two values and then check the string pool, then it realizes the value already exists in the pool so it just simply assign this reference to the String. now in more details:
Look at the compiled bytecode below of this simple program:
public class Test {
public static void main(String... args) {
String a = "hello world!";
String b = "hello" + " world!";
boolean compare = (a == b);
}
}
First the JVM loads the string "hello world! and then push it to string pool (in this case) and then loads it to the stack (ldc = Load constant) [see point 1 in Image]
Then it assign the reference created in the pool to the local variable (astore_1) [see point 2 in Image]
Notice that the reference created in the string pool for this literal is #2 [See point 3 in Image]
The next operation is about the same: in concatenates the string, push it to the runtime constant pool (string pool in this case), but then it realizes a literal with the same content already exists so it uses this reference (#2) and assign in to a local variable (astore_2).
Thus when you do (a == b) is true because both of them are referencing to the string pool #2 which is "hello world!".
Your example C is kind of different tho, because you're using the += operator which when compiled to bytecode it uses StringBuilder to concatenate the strings, so this creates a new instance of StringBuilder Object thus pointing to a different reference. (string pool vs Object)
String a = "ef";
String b = "cd" + a;
System.out.println("cdef"==b); // false
String c = "cd" + "ef";
System.out.println("cdef"==c); // true
when intern() method is invoked on a String object, It will try to find a String with the same sequence of characters in the pool.
if the String Pool already has a String with the same value then the reference of that String from the Pool is returned, otherwise the string is added to the pool, and the reference is returned.
String concatenation will only intern the strings if the expression is a Constant Expression
"cd" + a // is not a Constant Expression
Related
This question already has answers here:
How to Compare strings in java [duplicate]
(6 answers)
Closed 7 years ago.
String a = "x";
String b = "x";
System.out.println(a==b);
It prints "true" as it shares the same memory in String constant pool. But when I write the following code,
String a = "x";
String b = a + "y";
String c = "xy";
System.out.println(b==c);
Its printing false.
I know '==' compares the instances.
My Question is - why instance is not same in the second scenario. When creating a new String, It always checks whether the same string is available in the pool or not. Then after creating String b i.e. "xy" is available in the pool. So when I'm trying to create String c with the same "xy", it should not create new instance. It should share the same memory rather than creating a new instance. Then, Why in the second scenario the instances are different??
here, a + "y" creates a new String object hence, == returns false. It checks for object references and not object equality.
When comparing strings, you should use the equals method.
== operator checks whether both references variable refer to same object
equals() method checks there the contents of objects are same
Learn the difference between == operator and equals method in case of strings
Problem is String is immutable, every update operation on string results into new string, and the == check the instance and not its value in case of class types.
Try final:
final String b = a + "y";
or use equals():
System.out.println(b.equals(c));
Edited:
String literals are directly available in string pool it is not same in this case String b = a + "y", here its in heap. You can use intern() to make it available in string pool.
String b = (a + "y").intern();
System.out.println(a==b);//true
This might work, and the explanation for why can be found here.
String a = "x";
String b = a + "y";
String c = "xy";
System.out.println(b.equals(c));
if i create a string object as
String s=new String("Stackoverflow");
will String object created only in heap, or it also makes a copy in String constant pool.
Thanks in advance.
You only get a string into the constant pool if you call intern or use a string literal, as far as I'm aware.
Any time you call new String(...) you just get a regular new String object, regardless of which constructor overload you call.
In your case you're also ensuring that there is a string with contents "Stackoverflow" in the constant pool, by the fact that you're using the string literal at all - but that won't add another one if it's already there. So to split it up:
String x = "Stackoverflow"; // May or may not introduce a new string to the pool
String y = new String(x); // Just creates a regular object
Additionally, the result of a call to new String(...) will always be a different reference to all previous references - unlike the use of a string literal. For example:
String a = "Stackoverflow";
String b = "Stackoverflow";
String x = new String(a);
String y = new String(a);
System.out.println(a == b); // true due to constant pooling
System.out.println(x == y); // false; different objects
Finally, the exact timing of when a string is added to the constant pool has never been clear to me, nor has it mattered to me. I would guess it might be on class load (all the string constants used by that class, loaded immediately) but it could potentially be on a per-method basis. It's possible to find out for one particular implementation using intern(), but it's never been terribly important to me :)
In this case you are constructing an entirely new String object and that object won't be shared in the constant pool. Note though that in order to construct your new String() object you actually passed into it a String constant. That String constant is in the constants pool, however the string you created through new does not point to the same one, even though they have the same value.
If you did String s = "Stackoverflow" then s would contain a reference to the instance in the pool, also there are methods to let you add Strings to the pool after they have been created.
The new String is created in the heap, and NOT in the string pool.
If you want a newly create String to be in the string pool you need to intern() it; i.e.
String s = new String("Stackoverflow").intern();
... except of course that will return the string literal object that you started with!!
String s1 = "Stackoverflow";
String s2 = new String(s1);
String s3 = s2.intern();
System.out.println("s1 == s2 is " + (s1 == s2));
System.out.println("s2 == s3 is " + (s2 == s3));
System.out.println("s1 == s3 is " + (s1 == s3));
should print
s1 == s2 is false
s2 == s3 is false
s1 == s3 is true
And to be pedantic, the String in s is not the String that was created by the new String("StackOverflow") expression. What intern() does is to lookup the its target object in the string pool. If there is already a String in the pool that is equal(Object) to the object being looked up, that is what is returned as the result. In this case, we can guarantee that there will already be an object in the string pool; i.e. the String object that represents the value of the literal.
A regular java object will be created in the heap, and will have a reference s type of String. And, there will be String literal in String Constant Pool. Both are two different things.
My answer is YES!
Check the following code first:
String s0 = "Stackoverflow";
String s1 = new String("Stackoverflow");
String s2 = s1.intern();
System.out.println(s0 == s1);
System.out.println(s1 == s2 );
System.out.println(s0 == s2);
//OUTPUT:
false
false
true
s0 hold a reference in the string pool, while new String(String original) will always construct a new instance. intern() method of String will return a reference in the string pool with the same value.
Now go back to your question:
Will String object created only in heap, or it also makes a copy in String constant pool?
Since you already wrote a string constant "Stackoverflow" and pass it to your String constructor, so in my opinion, it has the same semantic as:
String s0 = "Stackoverflow";
String s1 = new String(s0);
which means there will be a copy in String constant pool when the code is evaluated.
But, if you construct the String object with following code:
String s = new String("StackoverflowSOMETHINGELSE".toCharArray(),0,13);
there won't be a copy of "Stackoverflow" in constant pool.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I compare strings in Java?
I am new to Java and I have difficulties in understanding String comparison. Can anyone explain the differences between the following scenarios?
Scenario 1 :
String a = "abc";
String b = "abc";
When I run the if(a == b) it returns true.
Scenario 2 :
String a = new String("abc");
String b = new String("abc");
and run if(a == b) then it returns false.
What is the difference?
== operator compares the references of two objects in memory. If they point to the same location then it returns true.String object in java are Immutable, so when you create Strings like in scenario1 then it didn't create new string. It just points the second string to the memory location of first string.
However, .equals() method compares the content of the String. When strings has same value then this method returns true.
So, in general it is recommended to use equals() method instead of ==.
It's because of Java String constant memory pool. Same valued literals are stored once.
String a = "abc";
String b = "abc";
// Now there is 1 string ("abc") and 2 references pointing to it.
String a = new String("abc");
String b = new String("abc");
// Now you have 2 string instances and 2 references.
Scenario 1 returns true because of a compiler optimization.
In general you should use equals() instead of == to compare strings.
In Java you need to use like this if(str.equals(str2)) which compares actual value of string rather than references.
Case1:
String a = "abc";
String b = "abc";
if(a == b)
In this case abc is cached in String constant pool thus a new string is not created String b = "abc"; b just refers to the string created by a it returns true as a and b both point to the same Object in the memory.
Case2:
String a = new String("abc");
String b = new String("abc");
and run if(a == b) then it returns false.
Here a two Strings are created and == operator just checks if two references point to the same reference, which it doesnt in this case thus it returns false
Two ways of creating string are
1) String s ="hello"; No. of string literal = 1 i.e. "hello" - No. of String objects on heap = 0
2) String s= new String("hello"); - No. of string literals =1 and No. of string objects =1
Java maintains a string pool of "LITERALS" and objects are going to stay on heap.
Advantage of string pooling: 1) Reduced memory usage*(PermGenSpace Issue) 2) Faster Comparision i.e == comparision 3) Faster lookup
Disadvantages: 1) Overhead of maintaining pool
How to pool String objects? Use Intern() on a string to add it to the pool. Downside of interning: 1) You may forget to intern some strings and compare them by == leading to unexpected results.
The reason is that the String literal "abc" will be turned into a global String instance for all its ocurrences, it will be the same String instance therefore you can be sure that "abc" == "abc". It is possible for the compiler to do that because String instances are immutable. However, if you explicitly allocate the String they will be two different instances and they will also be different to the String instance implicitly created by the compiler i.e. new String("abc") != new String("abc") and "abc" != new String("abc").
Another good example to understand what the compiler is doing is to look at this code:
"abc".contains("a");
you see that the literal behaves like an instance of a String type. You may exploit this to minimize programming errors e.g.
// this is OK and the condition will evaluate to false
String myStringValue = null;
if ("abc".equals(myStringValue)) { // false
whereas this code results in NPE:
// this will produce a NPE
String myStringValue = null;
if (myStringValue.equals("abc")) { // NPE
I have refernced the following links
What is String pool in Java?
Garbage collection and Strings
http://www.xyzws.com/Javafaq/what-is-string-literal-pool/3
Questions about Java's String pool
Still have some doubts please help me
`public class StrPool
{
public static void main(String[] args)
{
String abc="hello";
String abcd="hello";
System.out.println(abc==abcd);
}
}
`
In the above example OP : true
So we can confirm that both object are refered from same String object Am clear about that.
`String abc="hello World";
String abcd="hello";
System.out.println(abc==abcd);`
This gives output : false
So String pool is carried out when two String object having same literal???
If So two object of String will created in String pool??
Why second output is false ???
I READ THAT String class is immutable
abc and abcd have different object reference then Immutable means
" First String object will created by JVM and give two reference to abc and abcd " Am i right???
Thank you very much........
The second output is false as both the string abc and abcd having different content(text)
yes as you said String class is immutable ie their content does not gets changed, if in case you change the string text then JVM will allocate a new space instead of altering it.
Now when you create a new String reference with some text at that time JVM will check if that text already exists in pool and if then will refer your string to that text or else will create new text within pool
Java automatically applies String.intern to double quoted literals. Thus it is guaranteed that
String foo1 = "foo";
String foo2 = "foo";
assert foo1 == foo2;
However, for strings constructed other than as literals this is not guaranteed, i.e. given
String foo1 = "foo";
// contrived example, but imagine foo2 came from reading a file or similar
String foo2 = new String(new char[] { 'f', 'o', 'o' });
it is guaranteed that foo1.equals(foo2) but not necessarily that foo1 == foo2. You can call intern explicitly - it is guaranteed that foo1 == foo2.intern() - but it's generally clearer to use equals when you care about value equality and only use == when you really need reference equality.
Consider first code,
While executing statement String abc="hello", JVM will do following things
1. create a reference abc of type String.
2. check if literal "hello" is available in string pool
if available, it will assign its reference value to abc,
else it will create string literal "hello", assign its reference to abc and add it to String pool.
Same step will be repeated for String abcd="hello". Here, as "hello" is already available in string pool, same will be referred by abcd.
These same steps will be followed in second code block as well, (in fact everytime you create string object with such statement) just that the literal "hello world" and "hello" will be created differently and assigned to their respective variables.
I guess, now you can guess the reason behind the output of above two code samples.
String is immutable, means that you can not change any string object. Instead JVM will create new string object (or fetch one from string pool) and assign it to the reference.
e.g.
String varA = "hello"; -> 1
String varB = "hello"; -> 2
varA="world" -> 3
varB ="world" -> 4
At line 1, JVM will create String object "hello" in string pool and assign its reference to varA.
At line 2, JVM will assign the reference of "hello" object already present in String pool to varB.
At line 3, JVM will create a new object "world" and assign its reference to varA. Now String pool will have two objects , "hello" and "world".
At line 4, JVM will assign the reference of "world" object already present in String pool to varB. String pool will still have two objects , "hello" and "world".
So basically, JVM has not modified any String object, it has just modified the reference.
Hope it helps you. If you have any problem please comment.
So String pool is carried out when two String object having same literal???
--> Not exactly, String pool is carried out when you define literal string. If you create literal string object like String obj = "sometext" and While creating second literal like String obj1 = "some Other Text", obj1 contents will be compared to "sometext" by JVM. If both contents are equal like String str1 = "hello" and String str2 = "hello", then object references str1 and str2 will be pointed to same object("hello").
Why second output is false ???
--> because abc and abcd points to different string objects.
Immutable means: once object is created you can not change its contents.
I use the == in the code below and prints out "Equals!", why? Can someone explain why these two different strings a and b are equal?
public class test
{
public static void main()
{
String a = "boy";
String b = "boy";
if(a == b)
{
System.out.println("Equals!");
}
else
{
System.out.println("Does not equal!");
}
}
}
This is due to String interning.
Java (The JVM) keeps a collection of String literals that is uses to save memory. So, whenever you create a String like so:
String s = "String";
Java 'interns' the string. However, if you create the String like so:
String s = new String("String");
Java will not automatically intern the String. If you created your strings this way, your code would produce different results.
A quick Google search reveals lots of good resources regarding String interning.
This article will explain it in details:
What is the difference between == and equals() in Java?
After the execution of String a =
“boy”; the JVM adds the
string “boy” to the string
pool and on the next line of the code, it
encounters String b = ”boy” again; in this case the JVM already
knows that this string is already
there in the pool, so it does not create a
new string. So both strings a and b point to the same string what means they
point to the same reference.
String a = "boy"; will create a new string object with value ("boy"), place it in the string pool and make a refer to it.
When the interpreter sees String b = "boy";, it first checks to see if string "boy" is present in the string pool, since it is present, no new object is created and b is made to refer to the same object that a is referring to.
Since both references contain the same content they pass the equality test.
Because the run time will have a string pool and when you need to assign a new constant string, the run time look inside the pool, if the pool contains it, then they set the variable point to the same String object inside the pool.
But you should never depends on this to check for content string equals. You should use the method: equals
Whenever we create a string like below :
String str1 = "abc";
String str2 = "abc";
JVM will check the str2 = "abc" in the string constant pool, if it is present then it wont create a new String instead it point to the string one in the string constant pool.
But in case of this String str = new String("abc"); it will always create a new String Object but we can use intern() function to force JVM to look into the string constant pool.
As rightly explained above, in the case of '==' comparison, the runtime will look into the String pool for the existence of the string. However, it very much possible that during garbage collection, or during memory issues, the virtual machine might destroy the string pool. The "==" operator therefor might or might not return the correct value.
Lesson - Always use equals() for comparison.