String equality vs equality of location - java

String s1 = "BloodParrot is the man";
String s2 = "BloodParrot is the man";
String s3 = new String("BloodParrot is the man");
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
// output
true
true
false
true
Why don't all the strings have the same location in memory if all three have the same contents?

Java only automatically interns String literals. New String objects (created using the new keyword) are not interned by default. You can use the String.intern() method to intern an existing String object. Calling intern will check the existing String pool for a matching object and return it if one exists or add it if there was no match.
If you add the line
s3 = s3.intern();
to your code right after you create s3, you'll see the difference in your output.
See some more examples and a more detailed explanation.
This of course brings up the very important topic of when to use == and when to use the equals method in Java. You almost always want to use equals when dealing with object references. The == operator compares reference values, which is almost never what you mean to compare. Knowing the difference helps you decide when it's appropriate to use == or equals.

You explicitly call new for s3 and this leaves you with a new instance of the string.

Creating a String is actually a fast process. Trying to find any previously created String will be much slower.
Consider what you need to do to make all Strings interned. You need to search a set of all previously constructed Strings. Note this must be done in a thread-safe manner, which adds overhead. Because you don't want this to leak, you need to be using some form of (thread-safe) non-strong references.
Of course, you can't implement Java like this because the library unfortunately exposes constructors for Strings and most other immutable value objects.

The new keyword always makes a new string.
More detail here.

Why don't all the strings have the same location in memory if all three have the same contents?
Because they are different strings with same content!

There is a method called String.intern which, essentially, takes all Strings that are the same and puts them into a hash table (I am sort of lying, but for this it is the concept that matters, not the reality).
String s1 = "BloodParrot is the man";
String s2 = "BloodParrot is the man";
String s3 = new String("BloodParrot is the man").intern();
System.out.println(s1.equals(s2));
System.out.println(s1 == s2);
System.out.println(s1 == s3);
System.out.println(s1.equals(s3));
should have them all being "true". This is because (and I am lying a bit here again, but it still only matters for the concept not reality) String s1 = "BloodParrot is the man"; is done something like String s1 = "BloodParrot is the man".intern();

Related

Should we use String.intern in jdk 7 and +

I dont thnk i should ever use String.intern() in jdk7 and + ,Because of following reasons.
Java automatically interns String literals. This means that in many cases, the == operator appears to work for Strings in the same way that it does for ints or other primitive values.
Since interning is automatic for String literals, the intern() method is to be used on Strings constructed with new String()
String s1 = "Rakesh";
String s2 = "Rakesh";
String s3 = "Rakesh".intern();
String s4 = new String("Rakesh"); // why would i do this?
String s5 = new String("Rakesh").intern(); // looks stupid , better create like s1
s1,s2, s3 ,s4 point to same thing.
Your comments plz
String s3 = "Rakesh".intern();
This does nothing - the String object that represents the string literal is already in the string pool, so intern() does nothing here but just return the string that is already in the pool. It's the same as String s3 = "Rakesh";
String s4 = new String("Rakesh"); // why would i do this?
There is no reason ever to create a String object in this way, by passing it a string literal to the constructor. String objects are immutable and it is never necessary to explicitly create a copy of a string literal in this way.
String s5 = new String("Rakesh").intern(); // looks stupid , better create like s1
You already answered this yourself in the comment.
My advice: Forget about the intern() method - or keep it somewhere far away in the back of your mind. You don't need this method in 99,9% of the Java programs you are going to write. This method is only useful for very specific, rare occasions.
Just read the Java doc please.
When the intern method is invoked, if the pool already contains a
string equal to this String object as determined by
the equals(Object) method, then the string from the pool is
returned. Otherwise, this String object is added to the
pool and a reference to this String object is returned.

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 ==

String.trim() returning false for same referenced object

Why is this false?
String str1 = new String("Java ");
String str2 = str1;
System.out.println(str1.trim()==str2.trim()); //false
Initially str2 was referencing str1 object. So, comparing with == will return true for str1==str2
Then why is this false with .trim() method?
Even it returns false for literals (without new keyword)
String str1 = "Java "; //this is now without new keyword
String str2 = str1;
System.out.println(str1.trim()==str2.trim());
Note: I know how to use .equals method. But want to know == behavior especially in case of .trim() with above given two example.
use equal instead of ==
System.out.println(str1.equals(str2.trim()));
Use the equals() or equalsIgnoreCase() methods to compare Strings. == compares object identity.
Strings are immutable in Java.
Also string literals are interned i.e. java maintains a pool of string literals.
With the first 2 lines you are creating one object and 2 references str1 and str2 to the same object.
When trim() is applied on a string it forms a new string object and assigns the current reference to the new object.
But since new is used while object creation str1.trim() and str2.trim(), both end up creating 2 separate objects.
Refer: http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/String.html#trim%28%29
trim() method creates a new object. Since you applied trim() individually on same object (though referred to by multiple references str1 and str2) hence 2 new objects are created.
This is the reason why reference equality is not working.
String are compared with equals, not ==
"=="
works on refrences function trim creates a new object that will have new refrence. that is the reason it will allways return false
If you wanna compare the content of a string, you need .equeals.
Your (modified) example
String str1 = new String("Java ");
String str2 = str1;
System.out.println(str1.trim().equals(str2.trim())); //is now true
For string comparison you should use str1.equals(str2) or str1.equalsIgnoreCase(str2).
For more points check this question.
Since you are using String str1=new String("Java ");
You cannot use == operator
If you used String str1="Java ";, you could use ==
So here either change code to String str1="Java ";
or change
System.out.println(str1.trim().equals(str2.trim()));
You have two different Strings so two different references. To compare the content use equals().
== will compare the if reference of tow object are the same, as it check if both object are the same without checking the content of the object.
As string is an object == will work only with the same Object of type string without checking the content of the string.
to check the content of the String
use
equals() or equalsIgnoreCase
You are using == sign for comparison. In java this will compare the actual objects, that is, whether the two variables point to the same physical object in memory, the same memory location.
If you want to compare the actual content of the strings, then you need to use method equals of String class (or equalsIgnoreCase) if you don't care about the case.
The same applies to any other types of objects. If you compare them using ==, you will be comparing the physical memory location of two variables. You would use equals method to compare the actual content of the objects (provided the class actually implements this method).

Using == when comparing objects

Recently in a job interview I was asked this following question (for Java):
Given:
String s1 = "abc";
String s2 = "abc";
What is the return value of
(s1 == s2)
I answered with it would return false because they are two different objects and == is a memory address comparison rather than a value comparison, and that one would need to use .equals() to compare String objects. I was however told that although the .equals(0 methodology was right, the statement nonetheless returns true. I was wondering if someone could explain this to me as to why it is true but why we are still taught in school to use equals()?
String constants are interned by your JVM (this is required by the spec as per here):
All literal strings and string-valued constant expressions are interned. String literals are defined in ยง3.10.5 of the Java Language Specification
This means that the compiler has already created an object representing the string "abc", and sets both s1 and s2 to point to the same interned object.
java will intern both strings, since they both have the same value only one actual string instance will exist in memory - that's why == will return true - both references point to the same instance.
String interning is an optimization technique to minimize the number of string instances that have to be held in memory. String literals or strings that are the values of constant expressions, are interned so as to share unique instances. Think flyweight pattern.
Since you are not actually creating new instances of String objects for either one of these, they are sharing the same memory space. If it were
String s1 = new String("abc");
String s2 = new String("abc");
the result would be false.
The reason is strings are interned in Java. String interning is a method of storing only one copy of each distinct string value which is immutable. Interning string makes some string processing tasks more efficient. The distinct values are stored in a string intern pool.
(From wiki)
You're right that == uses memory address. However when the java compiler notices that you're using the same string literal multiple times in the same program, it won't create the same string multiple times in memory. Instead both s1 and s2 in your example will point to the same memory. This is called string interning.
So that's why == will return true in this case. However if you read s2 from a file or user input, the string will not automatically interned. So now it no longer points to the same memory. Therefor == would now return false, while equals returns true. And that's why you shouldn't use ==.
Quick and dirty answer: Java optimizes strings so if it encounters the same string twice it will reuse the same object (which is safe because String is immutable).
However, there is no guarantee.
What usually happens is that it works for a long time, and then you get a nasty bug that takes forever to figure out because someone changed the class loading context and your == no longer works.
You should continue to use equals() when testing string equality. Java makes no guarantees about identity testing for strings unless they are interned.
The reason the s1 == s2 in your example is because the compiler is simply optimizing 2 literal references in a scope it can predict.

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