why strings are showing different behaviour during concatenation? [duplicate] - java

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));

Related

How Java String pool works when String concatenation?

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

Java Strings Confusion [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 6 years ago.
String s1 = "abc";
String s2 = "abc";
String s3 = new String("abc");
String s4 = new String("abc");
if (s1 == s2) is giving true
while (s3 == s4) is giving false.
Can somebody give a detailed explanation onto what is String pool, heap, how many objects are created in each line and how many objects created in total.
Why s3==s4 is giving false?
A detailed explanation will be much appreciated.
When you do new String(...), it is evaluated at runtime and hence creates two different instances and you end up getting s3 == s4 as false. Same thing happens when you use StringBuilder and do something like sb.toString() which is again evaluated at runtime.
For Example,
StringBuilder sb = new StringBuilder();
String foo = sb.append("abc").toString();
String bar = new String("abc");
String foobar = "abc";
Here foo, bar and foobar are all different objects and hence foo == bar or foo == foobar will evaluate to false.
On the other hand s1 == s2 returns true because abc one declared, already exists in the String Pool and in this case both the objects points to the same reference in the pool.
String Class in java is defined in java.lang package and it is exactly that, a class and not a primitive like int or boolean.
Strings are developed to offer operations with many characters ans are commmonly used in almost all the Java applications
Some interesting facts about Java and Strings:
String in immutable and final in Java and in this case JVM uses String Pool to store all the String objects.
What are different ways to create String Object?
We can create String object using new operator like any normal java class or we can use double quotes (literal assignment) to create a String object.
There are too several constructors available in String class to get String from char array, byte array, StringBuffer and StringBuilderetc etc.
To your Question:
When we create a String using double quotes, JVM looks in the String pool to find if any other String is stored with same value. If found, it just returns the reference to that String object else it creates a new String object with given value and stores it in the String pool.
When we use new operator, JVM creates the String object but don’t store it into the String Pool. We can use intern() method to store the String object into String pool or return the reference if there is already a String with equal value present in the pool.
So when you do
String s1 = "abc";
String s2 = "abc";
those are checked in the StringPool and since s1 already exist there, s2 will take the same reference, hence, s1 ==s2 is true.
but when you do:
String s3 = new String("abc");
String s4 = new String("abc");
you are using the new operator, therefore the JVM is not checking if there is an string already in the heap, it will just allocate a new space for s4, so is s3==s4 ??? of course no.
Please take a look at the image below for a more illustrative example.

Java "abc" == "abc" operation [duplicate]

This question already has answers here:
What is the Java string pool and how is "s" different from new String("s")? [duplicate]
(5 answers)
Closed 7 years ago.
When we do:
String a = new String("abc");
String b = new String ("abc");
and do a a == b it returns false because they are 2 diferent objects.
But when we have this:
String c = "abc";
String d = "abc";
and we do a c == d it returns true. Why is that? Should it return false also? Why does the == operator behaves as a .equals() method in this case?
This happens because Java uses a so called Stringpool and tries to reuse old String-Literals to save some memory. But if you say "new String" you always create a new Object based on the Literal. See: here I would suggest you to always use the Objects.equals(a, b) if you want to make sure the objects are equal (or call equal on the Object itself if you're sure it's not null)

Confusion in declaring String Objects [duplicate]

This question already has answers here:
What is the difference between "text" and new String("text")?
(13 answers)
Closed 6 years ago.
If I declare a String as
String test=new String("testing");
and
String test1="testing1"
Since String is a class in JAVA how does test1 be a String Object without using a new Operator.Also,when a new Operator is used memory is assigned for new String("testing") so in the case of test1 how is the memory assigned?
Also,when the string is interned ,if two Strings have the same value with what reference is the String store once in the String intern pool?
Let us first consider this String test=new String("testing");
It creates an String Object in Heap.No Checking is done in String Pool for existence of this String in the pool.
and now this String test1="testing1"
It creates String a String Object in String Pool not in Heap.Before Creation check is done whether this string is already there in the pool.If yes its reference is returned else a new String is created in the pool and its reference is returned.Basically this is a String Literal, which is put in Constant pool for memory optimization and re-usability.
intern(): It is used when you construct an object using new() and you call intern() on that object then first a check is done in Stirng pool if that String already exists there or not,if yes it is directly used
Java has a separate memory for Strings that are created without calling the constructor with new. Every time such a String is created Java checks if that String is already in this memory. If it is, then Java sets the same reference to the new String until one of them changes.
When you create a String with the constructor using new then it behaves as a normal object in Java.
Take a look at this example:
String s1 = "Test";
String s2 = "Test";
When you compare this String with the == operator it will return true. s1.equals(s2) will also return true.
It looks different if you create String objects with the constructor like this:
String s1 = new String("Test");
String s2 = new String("Test");
When you now compare this Strings with the == operator it will return false, because the reference of this strings is now different (you created 2 unique String objects).
But if you use s1.equals(s2) it will return true as expected.
When you are using
String test1="testing1"
then it means you are storing only one copy of each distinct string value
but
String test=new String("testing");
gives you a new string object.
Consider your second assignment was:
String1 test1 = System.getenv("PATH");
Here, test1 is most probably also a reference to a String object, without using new().
You can assign references to already existing objects to new variables.
So where is the problem?
The problem is, you must not use sloppy wording like "test1 is a String object". It is not. It is a reference to a String object or null. That's all about it.

Understanding how string comparison works in Java [duplicate]

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

Categories