Java: String immutability and operator == [duplicate] - java

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I have this code which I cannot understand. In the beginning you can see two identical Strings, and when I compare them with use of operator == it says it is true, same as equals() method, but when I create two identical strings during runtime operator == says false. Why is this happening ?
Does it mean that when I hardcode identical strings they are placed in the same position in the memory and both references point to it? I found similar question, but there were no explicit answer.
public class StringTesting {
public static void main(String[] args){
String string1 = "hello"; //\
// } same place in the memory ?
String string2 = "hello"; ///
System.out.println(string1 == string2); //true
System.out.println(string1.equals(string2)); //true
String string3 = "hey";
String string4 = "he";
System.out.println(string3 == string4); //false
System.out.println(string3.equals(string4)); //false
string4 += "y";
System.out.println(string3 == string4); //false ????
System.out.println(string3.equals(string4)); //true
System.out.println(string3 + " " + string4); //hey hey
}
}

The following compound assignment operator:
string4 += "y";
performs String concatenation at runtime. Since the value of string4 is evaluated at runtime only. And String concatenation done at runtime creates a new object.
From JLS Section 3.10.5 (See towards the end of this section):
Strings computed by concatenation at run time are newly created and therefore distinct.
However if you perform concatenation of two string literals, it won't create a different objects. So the following code will return true:
"he" + "y" == "hey";
That JLS section contains code segment for various string concatenation example:
String hello = "Hello",
String lo = "lo";
System.out.print((hello == "Hello") + " "); // true
System.out.print((Other.hello == hello) + " "); // true
System.out.print((other.Other.hello == hello) + " ");// true
System.out.print((hello == ("Hel" + "lo")) + " "); // true
System.out.print((hello == ("Hel" + lo)) + " "); // false
System.out.println(hello == ("Hel" + lo).intern()); // true

string4 += "y"; creates a new object.
String literals however are placed in the same place in memory as an optimization (this is called string interning).

string1, string2, and string3 are all string constants. i.e., they appear as constant pool entries in the .class file. In Java, string constants are interned.
string4 is a new string, created by taking the string constant "he" and then appending "y". Therefore, it's not a string constant, and is not interned.
That is why string3 != string4.

Related

Why does the String.intern() method return two different results? [duplicate]

This question already has answers here:
Why are the results of of str == str.intern() for these strings different?
(4 answers)
Closed 3 years ago.
I have the code like this:
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1); //true
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == str2); //false
String str3 = new StringBuilder("Str").append("ing").toString();
System.out.println(str3.intern() == str3); //true
I can understand why str1.intern() == str1 and str3.intern() == str3 are true, but I don't understand str2.intern() == str2.
Why this is false?
My java version is: 1.8.0_73
String.intern() returns a String in the string literal pool. However if the string already exists in the pool, it will return the existing String.
If you pick a new String, it should return the String you created, but if you use a String which happens to exist in the pool already you will get the existing String.
It is reasonable to assume that in this case "java" already exists in the pool so when you call intern() it returns a different object so == is false.
note: string.intern().equals(string) should always be true.
The constant String "java" already exists in the Java constant pool, but you can verify that by changing
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern()==str2);
to
String str2 = new StringBuilder("ja").append("va").toString();
System.out.println(str2.intern() == "java");
which will get the same constant and output
true
Alternatively, you could add "计算机软件" and "String" to the constant pool like
String a = "计算机软件";
String b = "String";
String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println(str1.intern() == str1);
String str3 = new StringBuilder("Str").append("ing").toString();
System.out.println(str3.intern() == str3);
Then you would get (consistent with your observations)
false
false

Java: == in print statement gives different answers [duplicate]

This question already has answers here:
String equals and == with String concatenation [duplicate]
(4 answers)
Closed 7 years ago.
String a = "abc";
String b = "abc";
System.out.println("Result .... " + a==b); // false
System.out.println(a==b); // true
1st print statement prints false and 2nd prints true, though ideally it has to be true. Why is it false in 1st print statement ?
System.out.println("Result .... " +a==b); -> the result string will be appended with 'a' and then compares with b so it results false.
Order of operations:
"Result .... " + a==b
is equivalent to
("Result .... " +a) == b
which will be false since the two strings are not the same reference.
The explanation for this is that the + addition operator has a higher precedence than == logical equivalence.
The expression a == b is returning true in your second statement due to interning, in which a and b actually refer to same string object.
Click here for a link to Oracle's table of operator precedence in Java.
Forgot checking equality by == in java. In Java this operation checks equality of object link. Additionally it is applicable for checking equality of simple numbers. You should use .equals method
String a = "abc";
String b = new String(a);
System.out.printLn(a == b);//false
System.out.println(a.equals(b));//true
Learn about operation order in java
It is because in "Result .... " +a==b it first add "Result .... " with a and then == to b. If you write like this "Result .... " +(a==b), then it will be OK.
In the first statement, you're comparing "Result .... " + a with b. In the second one, you're comparing a with b, hence the difference. Change your first statement as follows:
System.out.println("Result .... " + (a==b));
And keep in mind that strings should be compared using the equals() method instead of ==.
System.out.println("Result .... " +a==b);
String Result is appended with 'a' and then compares with b so it provides false. (Result .... a == b) which is false.
Follow this link to understand precedence of operators in java and this.
Operator + has more precedence than == operator.
try adding brackets, you will see the diff. Bracket is evaluated separately.
public static void main(String[] args) {
String a = "abc";
String b = "abc";
System.out.println("Result .... " + (a == b)); // false
System.out.println(a == b); // true}
}
output
Result .... true
true

How + internally works on Strings in JAVA

I read from the blogs that internally java use StringBuilder to concat the String when we use + operator. I was just checking it and found some strange outputs.
public class StringDemo {
public static void main(String[] args) {
String a = "Hello World";
String b = "Hello World";
String c = "Hello";
String d = c + " World".intern();
String e = new StringBuilder().append(String.valueOf(c)).append(" World").toString().intern() ;
String f = new StringBuilder(String.valueOf(c)).append(" World").toString().intern();
System.out.println(a == b); // Line 1 Expected output true
System.out.println(a == d); // Line 2 Output is false
System.out.println(a == e); // Line 3 Output is true
System.out.println(a == f); // Line 4 Output is true
}
}
So i am using + operator to concat two strings c & " World" and then use intern() method to move String in the pool for String d.
As per my understanding java use StringBuilder, so now I use StringBuilder to concat the String and use intern() method for Strings e and f.
So if both the equivalent then address of both the String must be same but the output of Line 2 not matching with Line 4 & 5.
Thanks in advance for your valuable feedback.
How + internally works in JAVA
Here is my post on the same, give a read Compiler version : How String concatenation works in java.
And coming to your code inside
System.out.println(a == d);
That should be false only.
As per your understanding you are expecting true. No. Your understanding is wrong. There is a clear difference between
String d = c + " World".intern();
And
String d = (c + " World").intern();
In first line only "World" got interned and the second line "Hello World" got interned
When you do (c + " World").intern(), you'll see the output true.

strange effect with string comparisation with == [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
I know that we shouldn't compare Strings with == and its better to use equals.
For so far I learned this should all be false.
So why does the first method return true?
private String ab = "AB";
private String ab2 = "A" + "B";
private String a = "A";
private String b = "B";
private String ab3 = a + b;
public void test () {
System.out.println("ab == ab2" + ab==ab2);
System.out.println("ab == ab3" + ab==ab3);
System.out.println("ab == a+b" + ab==(a+b));
}
Because the concatenation of literal Strings are compiled into a single String, which will also be interned in the String pool. This code:
private String ab2 = "A" + "B";
is compiled to
private String ab2 = "AB";
ab and ab2 point to the same literal String "AB", thus they're ==s.
Still, you should not trust comparison of Strings with ==, you should always compare their equality using equals method.
It is called String interning:
http://en.wikipedia.org/wiki/String_interning
To summarize, since strings are immutable in Java, JVM optimizes by creating only one object for two string literals that are equal. Therefore, comparison returns true.

String Comparison in Java...? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How do I compare strings in Java?
why first comparison ( s1 == s2 ) displays equal whereas 2nd comparison ( s1 == s3 ) displays not equal....?
public class StringComparison
{
public static void main( String [] args)
{
String s1 = "Arsalan";
String s2 = "Arsalan";
String s3 = new String ("Arsalan");
if ( s1 == s2 )
System.out.println (" S1 and S2 Both are equal...");
else
System.out.println ("S1 and S2 not equal");
if ( s1 == s3 )
System.out.println (" S1 and S3 Both are equal...");
else
System.out.println (" S1 and S3 are not equal");
}
}
This has to do with the fact that you cannot compare strings with == as well as compiler optimizations.
== in Java only compares if the two sides refer to the exact same instance of the same object. It does not compare the content. To compare the actual content of the strings, you need to use s1.equals(s2).
Now the reason why s1 == s2 is true and s1 == s3 is false is because the JVM decided to optimize the code so that s1 and s2 are the same object. (It's called, "String Pooling.")
Per 3.10.5: Pooling of string literals is actually mandated by the standard.
Moreover, a string literal always refers to the same instance of class
String. This is because string literals - or, more generally, strings
that are the values of constant expressions (§15.28) - are "interned"
so as to share unique instances, using the method String.intern.
Don't use == to compare strings, it tests reference equality (do two names refer to the same object). Try s1.equals(s2);, which actually tests the elements for equality.
String one = "Arsalan";
String two = "Arsalan";
one == two
// Returns true because in memory both Strings are pointing to the SAME object
one.equals(two)
// Will ALWAYS return true because the VALUES of the Strings are the same (would not matter if the objects were referenced differently).
The reason is string interning. It's complicated. The compiler is "smart" enough to use the same exact object for s1 and s2, even though you might think they are different. But s3, which uses new String("Arsalan"), doesn't intern.
Some guidelines:
You should almost always use equals(), not ==, to compare strings
You should almost never use String s = new String("foo").
Instead, use String s = "foo".
If "Arsalan" is not found in the pool of Strings, a "Arsalan" string will be created and s1 will refer it. Since "Arsalan" string already exists in the pool of Strings s2 will refer to the same Object as s1. Because the new keyword is used for s3, Java will create a new String object in normal (nonpool) memory, and s3 will refer to it. This is the reason why s1 and s3 don't refer to the same object.
public class StringComparison
{
public static void main( String [] args)
{
String s1 = "Arsalan";
String s2 = new String("Arsalan");
String s3 = new String ("Arsalan");
if ( s1 == s2 )
System.out.println (" S1 and S2 Both are equal...");
else
System.out.println ("S1 and S2 not equal");
if ( s1 == s3 )
System.out.println (" S1 and S3 Both are equal...");
else
System.out.println (" S1 and S3 are not equal");
if ( s2 == s3 )
System.out.println (" S2 and S3 Both are equal...");
else
System.out.println (" S2 and S3 are not equal");
}
}
If you run this, you can see that S2 and S3 are also not equal. This is because s2, s3 are references to a String Object and hence they contain different address values.
Don't use ==, use s1.equals(s2) or s1.equals(s3) instead.

Categories