strange effect with string comparisation with == [duplicate] - java

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.

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

Build a String with String Operators [duplicate]

This question already has answers here:
String Constant Pool
(5 answers)
Closed 7 years ago.
In this example I thought that the result was true. I thought that the variable stored in the string pool.
The answer was: returns false because the two String objects are not the same in memory. One comes directly from the string pool and the other comes from building using String operations.
String a = "";
a += 2;
a += 'c';
a += false;
if ( a == "2cfalse") System.out.println("==");
I do not understand where the variable a was stored
Okay, so two responses to this. First, the ethically correct one, do never test strings with ==, always use .equals() or .equalsIgnoreCase().
Secondly, it's true that indeed, "a" == "a" because the strings are stored in, as you call it, the same pool. The problem here is that you append to it. Appending to a string causes it to become a different string, which is not stored in the string pool. The string pool is only generated on-compile, and as the second string is calculated on runtime, it won't match the one generated on-compile.
Imagine a string-pool to work like this:
a = "test";
b = "te";
c = "st";
d = "test";
The compiler translates this into
sp1 = "test";
sp2 = "te";
sp3 = "st";
a = sp1;
b = sp2;
c = sp3;
d = sp1;
Now == will check if two variables refer to the same sp. If you run b + c java will not go back and check if any of the sp's is the same as that. It only does that on compile.

Converted charAt() doesnt equals to the same String [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 7 years ago.
My problem is hidden in next code:
public class saturo {
public String primer, d;
public void start() {
primer = "545640";
//d = "0";
d = String.valueOf(primer.charAt(((primer.length())-1)));
if(d == "0"){
System.out.println("This is equal: d == " + d);
}else{
System.out.println("This is not equal: d == " + d);
}
}
public static void main(String args[]) {
new saturo().start();
}
}
So as you see, the problem is that if i declare String d as "0" than the program will execute it as d is equal to "0" and return true;
But if i get character "0" from a String, convert it to String, and check if this equals to "0" then i have got a false.
I have checked if there is something wrong with character encode, but not, its right in any case. No type mismatches.
Where in this the logic?
If you want to compare the value of 2 strings, you need to use .equals()
So you would do:
if(d.equals("0"){
// your code here
}
Using == compares the strings by reference (same spot in memory) where .equals() compares the value of the strings.
use .equals not == you are comparing by reference not value

Difference in the following declarations [duplicate]

This question already has answers here:
Comparing strings with == which are declared final in Java
(6 answers)
What is the difference between these two ways of initializing a String?
(3 answers)
Closed 7 years ago.
I am unable to recognize the difference in the following declarations of Strings in Java.
Suppose I am having two string
String str1="one";
String str2="two";
What is the difference between
String str3=new String(str1+str2);
and
String str3=str1+str2;
In both the above declarations, the content of str3 will be onetwo.
Suppose I create a new string
String str4="onetwo";
Then in none of the above declarations,
if(str4==str3) {
System.out.println("This is not executed");
}
Why are str3 and str4 not referring to the same object?
str1 + str2 for non-compilation-constant strings will be compiled into
new StringBuilder(str1).append(str2).toString(). This result will not be put, or taken from string pool (where interned strings go).
It is different story in case of "foo"+"bar" where compiler knows which values he works with, so he can concatenate this string once to avoid it at runtime. Such string literal will also be interned.
So String str3 = str1+str2; is same as
String str3 = new StringBuilder(str1).append(str2).toString();
and String str3 = new String(str1+str2); is same as
String str3 = new String(new StringBuilder(str1).append(str2).toString());
Again, strings produced as result of method (like substring, replace, toString) are not interned.
This means you are comparing two different instances (which store same characters) and that is why == returns false.
Java does not have memory of "how this variable got the value", therefore it really does not matter which method you use, if the result is same.
About comparing, if you compare strings with ==, you are comparing address of objects in memory, because String is not primitive data type, not values. You have to use if(str4.equals(str3))
Because Strings in Java are immutable the compiler will optimize and reuse String literals. Thus
String s1 = "one";
String s2 = "one";
s1 == s2; //true because the compiler will reuse the same String (with the same memory address) for the same string literal
s1 == "o" + "ne"; //true because "Strings computed by constant expressions are computed at compile time and then treated as if they were literals"
s3 = "o";
s1 == s3 + "ne"; //false because the second string is created a run time and is therefore newly created
for a reference see http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#jls-3.10.5
Strings are kind of tricky, because there is some effort to share their representation. Plus they're immutable.
The short answer is: unless you're really working in a low level, you should never compare strings using "==".
Even if it works for you, it will be a nightmare for your teammates to maintain.
For a longer answer and a bit of amusement, try the following:
String s1= "a" + "b";
String s2= "a" + "b";
String s3=new String("a"+"b");
System.out.println(s1==s2);
System.out.println(s3==s2);
You'll notice that s1==s2 due to the compiler's effort to share.
However s2 != s3 because you've explicitly asked for a new string.
You're not likely to do anything very smart with it, because it's immutable.

Java: String immutability and operator == [duplicate]

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.

Categories