Why DOES == sometimes work on Strings in Java? [duplicate] - java

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 7 years ago.
I have the following code:
Circle c1 = new Circle();
Circle c2 = new Circle();
System.out.println(c1 == c2);
Which outputs False, as expected. This is because c1 and c2 are reference types and "==" checks if they refer to the same type (which they don't).
However, I recently tried this:
String a = "hello";
String b = "hello";
System.out.println(a == b);
Which for some reason outputs True. Why is this? String is a reference type and a and b refer to different memory locations. I was always taught that you need to use .equals() for this to work, which this does not!
See: https://ideone.com/CyjE49
UPDATE
THIS IS NOT A DUPLICATE!
I know the proper way to compare strings is using .eqauls()
UPDATE 2
This question may have an answer in: How do I compare strings in Java?, but the question there wasn't asking what I am asking and the answer just went in more detail than required.
Therefore searching with my same question (on Google or otherwise) means users won't be sent to that question or may dismiss it entirely due to the title of the question. Therefore it may be a good idea to keep this up for benefit of other users!

Because string literals are intern'd, identical literals refer to the same object. Therefore, checking for reference equality between them will necessarily return true.
From the Java Language Specification (3.10.5):
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.
In practice, the compiler will pool the string literals "early" and store only one copy in the compiled .class file. However, identical string literals from separate class files will still compare equal using == since the literals are still intern'd when the classes are loaded.
If, on the other hand, we properly apply your example with Circle to String, we would have:
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // will print false!
In this case we explicitly create new objects, so they cannot be equal references.
Any string constructed by means other than a literal or other constant string expression will also not necessarily compare reference-equal with an identical string. For example:
String a = "hello";
String b = "hello";
System.out.println(a.substring(0,3) == b.substring(0,3)); // may print false!

String interning. Since both a and b are constants with the same value, the compiler takes advantage of the String's immutability to have both variables refer to the same string and thus save space. Therefore == returns True, since they're effectively the same object.

In this case, "hello" is treated as a constant which is assigned to a and b. So here == actually returns true. If you do this:
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b);
You will get false.

Related

Can anyone please explain why output of the following is such? [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 8 years ago.
String str1 = "abc:5";
String str2 = "abc:" + str1.length();
String str3 = "abc:" + 5;
System.out.println(str1==str2);
System.out.println(str1==str3);
Output of the program is :
false
true
But I don't understand why?
== operator will compare reference only
.equals() will compare the values.
in your case
str1==str2 // compares the two references, which are different.
had it been, str1.equals(str2), it would have compared the values, which will return true
The “==” operator
In Java, when the “==” operator is used to compare 2 objects, it checks to see if the objects refer to the same place in memory. In other words, it checks to see if the 2 object names are basically references to the same memory location.The “==” operator compares the objects’ location(s) in memory
The “equals” method
The Java String class actually overrides the default equals() implementation in the Object class – and it overrides the method so that it checks only the values of the strings, not their locations in memory.
Here str1 = "abc:5"; is located in constant pool of string and str2 is concatenated with 2 different object with new operator. So both str1 and str2 are referring to different object. That's the reason it is showing false.
The == operator is used for only reference variables in java. For example if you are comparing characters a1 and a2 you can use the == operator because the char type is highlighted in most IDEs in Java. To check if two Strings are equal to each other you can use .equals()or .equalsIgnoreCase() to compare the Strings. This is because Strings are objects, not primitives, and require their own method in the class to test if Strings are the same.
For the first System.out.println(); statement, you would use System.out.println(str1.equals(str2)); or System.out.println(str1.equalsIgnoreCase(str2));.
For the second System.out.println(); statement, you would use System.out.println(str1.equals(str3)); or System.out.println(str1.equalsIgnoreCase(str3));.

Comparing two strings with equal(==) operator [duplicate]

This question already has answers here:
String comparison and String interning in Java
(3 answers)
Closed 9 years ago.
I was kind of telling some one that , we must use String.equals method to compare two strings values, we can not simply use == operator in java to compare Strings, and told him that == will return false as it doesn't compare the string value but String object reference value.
I have written this example to show him, but for my surprise it always prints true for == operator..
here is the code
public void exampleFunc1(){
String string1 = "ABC";
String string2 = "ABC";
if(string1 == string2)
System.out.println("true");
else{
System.out.println("false");
}
System.out.println(" Are they equal "+(string1 == string2)); // this shouldn't print True but it does
System.out.println(" Are they equal "+(string1.equals(string2)));
}
Output:-
Are they equal true
Are they equal true
So question here is in what circumstances == operator on objects can print true, except that both objects are same instance?
String is one of a few special cases.
Class String keeps a special pool of "interned" Strings. Method myString.intern() looks up myString in this pool. If another String with the same contents already exists in the pool, a pointer to it is returned. If not, myString is added (and a pointer returned).
When you say myString= myString.intern() ;, you are effectively making myString refer to a shared copy or its underlying String available for future sharing (and no duplication). Most library methods creating Strings are subject to this, particularly String literals.
Other cases of "interning" occur with wrapper types Integer, Long, etc. They don't have constructors, but static methods valueOf() that return pre-built, shared objects when they can (usually the 256 values closest to zero), and new objects when they can not. The later is not much problematic because these types are more lightweight than Strings. Long, for example, has a payload of just 8 bytes. String contains a char[] that even empty is 16 bytes or so.
To answer your question, you can not count on any "interning" mechanisms. They have changed in the past, and they could change in the future (or even from one JVM to another), making your code unusable. Always use equals.
You should use
String string1 = new String("ABC");
String string2 = new String("ABC");
Then everything would be correct like what you think,
In this case, "ABC" is just a reference to a const string.
The compiler may be optimizing the assignments and only creating one String object. If you use the explicit String constructor, the == operation should behave as expected.

Is it more proper to use the equivalent operator or the equals() method to compare the contents of Strings? [duplicate]

This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I'm reading about the notion of interned strings:
String s1 = "Hi";
String s2 = "Hi";
String s3 = new String("Hi");
System.out.println(s1 == s2); // true
System.out.println(s1 == s3); // false
System.out.println(s1.equals(s3)); //true
String is an object in Java, but the compiler allows us to use a literal for assigning to a String reference variable, instead of requiring us to use the new operator, because of the ubiquity of strings in programming. The use of the literal for assignments creates an interned string. All interned strings with the same literal point to the same space in memory, thus the equivalent operator is permitted.
It got me wondering, however: would it not be more proper to use the equals() method to compare two string reference variables, given that in Java strings are objects (and not arrays like in other languages) and the contents of objects should be compared using equals(), as the == operator in regards to objects only tells us that they point to the same spot in memory?
Or is it not more proper because the very concept of interned strings makes it clear that one String can only be equivalent (==) to another string if they share the same literal?
If it is more proper, do people commonly use the equals() method regardless, or is it considered overkill?
Yes equals is the method used to compare the contents of string objects. Using == we can only compare whether the two references point to the same memory location or not. But using equals you can check whether two references hold the same string content, be them at the same memory location or not. Logically speaking, when you are trying to compare two strings, you must be looking for comparing the contents of those strings and not the memory locations of them.
As a practice or almost everywhere string equals method is used for string comparision and not ==

== operator does not compare references for String [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
String comparison and String interning in Java
I understand how String equals() method works but was surprised by some results I had with the String == operator.
I would have expected == to compare references as it does for other objects.
However distinct String objects (with the same content) == returns true and furthermore even for a Static String object (with the same content) which is obviously not the same memory address.
I guess == has been defined the same as equals to prevent its misuse
No, == does just compare references. However, I suspect you've been fooled by compile-time constants being interned - so two literals end up refererring to the same string object. For example:
String x = "xyz";
String y = "xyz";
System.out.println(x == y); // Guaranteed to print true
StringBuilder builder = new StringBuilder();
String z = builder.append("x").append("yz").toString();
System.out.printn(x == z); // Will print false
From section 3.10.5 of the Java language specification:
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.
The reason it returns the same is because of memory optimizations (that aren't always guaranteed to occur) strings with the same content will point to the same memory area to save space. In the case of static objects they will always point to the same thing (as there is only one of it because of the static keyword). Again don't rely on the above and use Equals() instead.
One thing I should point out from Jon Skeet is that it is always guaranteed for compile time constants. But again just use equals() as it is clearer to read.
It is due to string intern pooling
See
whats-the-difference-between-equals-and
The == operator does always compares references in Java and never contents. What can happen is that once you declare a string literal, this object is sent to the JVM's string pool and if you reuse the same literal the same object is going to be placed in there. A simple test for this behavior can be seen in the following code snippet:
String a = "a string";
String b = "a string";
System.out.println( a == b ); // will print true
String c = "other string";
String d = new String( "other string" );
System.out.println( c == d ); // will print false
The second case prints false because the variable d was initialized with a directly created String object and not a literal, so it will not go to the String pool.
The string pool is not part of the java specification and trusting on it's behavior is not advised. You should always use equals to compare objects.
I guess == has been defined the same as equals to prevent its misuse
Wrong. What is happening here is that when the compiler sees that you are using the same string in two different places it only stores it in the program's data section once. Read in a string or create it from smaller strings and then compare them.
Edit: Note that when I say "same string" above, I'm referring only to string literals, which the compiler knows at runtime.

How "==" works for objects?

public static void main(String [] a)
{
String s = new String("Hai");
String s1=s;
String s2="Hai";
String s3="Hai";
System.out.println(s.hashCode());
System.out.println(s1.hashCode());
System.out.println(s2.hashCode());
System.out.println(s3.hashCode());
System.out.println(s==s2);
System.out.println(s2==s3);
}
From the above code can anyone explain what is going behind when JVM encounters this line (s==s2) ?
It compares references - i.e. are both variables referring to the exact same object (rather than just equal ones).
s and s2 refer to different objects, so the expression evaluates to false.
s and s1 refer to the same objects (as each other) because of the assignment.
s2 and s3 refer to the same objects (as each other) because of string interning.
If that doesn't help much, please ask for more details on a particular bit. Objects and references can be confusing to start with.
Note that only string literals are interned by default... so even though s and s2 refer to equal strings, they're still two separate objects. Similarly if you write:
String x = new String("foo");
String y = new String("foo");
then x == y will evaluate to false. You can force interning, which in this case would actually return the interned literal:
String x = new String("foo");
String y = new String("foo");
String z = "foo";
// Expressions and their values:
x == y: false
x == z: false
x.intern() == y.intern(): true
x.intern() == z: true
EDIT: A comment suggested that new String(String) is basically pointless. This isn't the case, in fact.
A String refers to a char[], with an offset and a length. If you take a substring, it will create a new String referring to the same char[], just with a different offset and length. If you need to keep a small substring of a long string for a long time, but the long string itself isn't needed, then it's useful to use the new String(String) constructor to create a copy of just the piece you need, allowing the larger char[] to be garbage collected.
An example of this is reading a dictionary file - lots of short words, one per line. If you use BufferedReader.readLine(), the allocated char array will be at least 80 chars (in the standard JDK, anyway). That means that even a short word like "and" takes a char array of 160 bytes + overheads... you can run out of space pretty quickly that way. Using new String(reader.readLine()) can save the day.
== compars objects not the content of an object. s and s2 are different objects. If you want to compare the content use s.equals(s2).
Think of it like this.
Identical twins look the same but they are made up differently.
If you want to know if they "look" the same use the compare.
If you want to know they are a clone of each other use the "=="
:)
== compares the memory (reference) location of the Objects. You should use .equals() to compare the contents of the object.
You can use == for ints and doubles because they are primitive data types
I suppose you know that when you test equality between variables using '==', you are in fact testing if the references in memory are the same. This is different from the equals() method that combines an algorithm and attributes to return a result stating that two Objects are considered as being the same. In this case, if the result is true, it normally means that both references are pointing to the same Object. This leaves me wondering why s2==s3 returns true and whether String instances (which are immutable) are pooled for reuse somewhere.
It should be an obvious false. JVM does a thing like using the strings that exist in the Memory . Hence s2,s3 point to the same String that has been instantiated once. If you do something like s5="Hai" even that will be equal to s3.
However new creates a new Object. Irrespective if the String is already exisitng or not. Hence s doesnot equal to s3,s4.
Now if you do s6= new String("Hai"), even that will not be equal to s2,s3 or s.
The literals s2 and s3 will point to the same string in memory as they are present at compile time. s is created at runtime and will point to a different instance of "Hai" in memory. If you want s to point to the same instance of "Hai" as s2 and s3 you can ask Java to do that for you by calling intern. So s.intern == s2 will be true.
Good article here.
You are using some '==' overload for String class...

Categories