This question already has answers here:
How do I compare strings in Java?
(23 answers)
String Constant Pool
(5 answers)
Closed 8 years ago.
Consider this piece of code:
String baz = "Hello";
String foo = "Hello";
return foo.equals(baz); // Returns true as expected
return(baz == foo); // Also returns true!
Why does the == operator also return true in this case? It should be comparing the locations of the objects themselves, not their values.
I'm assuming that Java does some sort of internal work and determines these two are of type String (or Integer, etc.) so it implicitly calls the .equals() method.
I'm curious to know exactly how this is done (ie. what goes on in the background), and why this is done, what if I actually wanted to test their location in memory?
return(baz == foo) is also returning true because all literal strings are interned in Java. 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.
So in short due to use of String intern pool for your case return(baz == foo) is behaving same as return(baz.equals(foo))
Read more about String literals in Java Specs
Related
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 3 years ago.
Why does this return true?
This seems a little odd since I have two Strings which are separate objects but are said to be aliases of each other.
public boolean stringEquals() {
String tmp1 = "hello";
String tmp2 = "hello";
return tmp1==tmp2;
}
String literals are interned by the JVM, so their reference will be the same.
In other words, each String literal used will be stored exactly once, hence their object will be similar. See
Taken from here: https://www.geeksforgeeks.org/interning-of-string/
The == operator compares the reference of the 2 objects and not their values. So unless we use .equals() we must expect to see false as these are 2 separate objects.
But this special case happens with strings. In Java Strings are immutable. Meaning their value cannot change. JVM uses this property to optimize memory. The strings in Java are stored in a separate space in memory called String Pool. Since these 2 strings are the same and that they are immutable, JVM stores "hello" in the pool and reuses the same reference for both objects. This is safe as strings are immutable. ( If you assign it something else later in code, it would create a new value elsewhere in pool and reference to it).
At the same time it is interesting to note that this isn't the case when using constructor. If we use the constructor to construct a new string, it always creates a separate object with unique reference regardless of whether the value is same or not.
String a = new String("Hello");
String b = new String("Hello");
return a==b;
Would return false.
The string pool concept applies only when using string literals without the constructor.
I have a scenario like this -
String s = "abc", t="abc"; //LINE 1
System.out.println(s==t); // definitely it would return true; //LINE 2
s=s+"d"; t=t+"d"; //LINE 3
System.out.println(s==t); // output would be false; but why??
s=s.intern(); t=t.intern();
System.out.println(s==t); // it would return true;
I wanted to know why the second print statement returned false. Please provide me any reference link which explains the same.
While creating t at line 1; intern was called and it pointed to "abc" why not intern was called at line 3?
java strings are immutable.
that means that when you do something like s=s+"d" youre actually creating a whole new string, and assigning it to s.
on top of that, the compiler does constant detection and allocation, so that when you write s="abc", t="abc" the compiler re-uses the same reference and your code is effectively s=t="abc"
so you start with the exact same string instance (thanks to compiler optimization) and turn it into 2 identical yet different strings, at which point s==t is false (s.equals(t) would have been true, as it compares the contents and not the address in memory).
next up is intern(). what intern() does is looks up an identical string in the string cache and returns it. if it doesnt find an identical entry it places the argument provided into the cache and returns the argument. so s=s.intern() places s into the string cache and returns it (so s is unchanged) but the following call t=t.intern() actually returns s, so that s==t again.
Strings are "special" Java objects.
The JVM tries to reuse the same references (that's why String s = "abc", t="abc"; causes s and t to point to the same instance), however, when working on instances (like t=t+"d") a new instance gets created, thus, the references are not the same
In order to compare strings you have to use the .equals() method.
intern() causes to create a canonical representation out of the string pool inside the String class (
http://docs.oracle.com/javase/7/docs/api/java/lang/String.html#intern%28%29)
String s = "abc", t="abc";
s == t is true because Java automatically interns String literals. In this case the String literal "abc" has been interned and both s and t point to that same instance. Hence s == t is true.
s = s + "d"; t = t + "d";
Strings in Java are immutable. Hence what you are assigning to s and t are two new Strings that have been constructed. Therefore they do not point to the same instance. This is why s == t returns false.
s = s.intern(); t = t.intern();
Here you have forcibly interned the string in s.intern(). Since both s and t contain the same string values, the JVM sees that t is the same and makes it point to the same interned-instance as s. Hence s == t is true.
As a general note, establishing the equality of strings should be done via .equals() and not ==; == only compares references for reference-types and not values.
Java Language Specification explicitly covers this particular situation. Here is a quote from chapter 3.10.5. "String Literals":
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.
As you can see, only constant expressions are interned. So, first four lines of your code are equivalent to:
String s = "abc".intern(), t="abc".intern();
System.out.println(s==t);
s=s+"d".intern(); t=t+"d".intern();
System.out.println(s==t);
Expressions s+"d" and t+"d" aren't constant and, thus, aren't interned.
JLS even provides an example with useful notes. Here is the relevant part:
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == ("Hel"+lo)));
}
}
Output: false
Note: Strings computed by concatenation at run time are newly created and therefore distinct.
Because when you concatenate Strings you generate a new object reference except when they are literal Strings.
Note that the intern of both Strings point to the same literal String object reference.
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I was wondering: Why does this code result in false?
Coz == operator should return true when it's the same memory point.
public static void main(String[] args) {
String a = new String("hello");
System.out.println(a == "hello");
}
Can you describe why this happens.
Java compares references when you compare (==) objects. Since you create two new objects, they do have different addresses in memory regardless of their content.
String literals are created on what is called: Pool Memory.
However, when one creates a String with explicitly new keyword, he actually creates a new String object, independent of the pool memory's one. Meaning that both references are not the same at all.
In your sample, you could solve the case by both ways:
_ use java.lang.String.intern method: placing your explicitly created String into the pool memory.
_ use only literals to create/reuse String.
For information, Pool Memory was created in order to avoid some useless creation of common/redundant literal Strings, thus optimizing memory space.
Similar concept exists for Integer: Integer caching in Java
This happens because there are two String objects here - first is the literal and the other is the one created with new String. When you create explicitly a new String object it the String from pool is not reused.
It is well described in details http://theopentutorials.com/tutorials/java/strings/string-literal-pool/
The command String a = new String("hello"); creates a String object in the non-pool part of the memory, and then a refers to it. And then "hello" is placed in the String pool. Whereas while comparing, a == "hello" the "hello", is in the String pool. So, the reference of both the objects are different, although the content of both the objects is same. Had to declared a, in the following manner, the comparison would had returned true
String a = "hello";
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
When should we use intern method of String?
what is string interning?
Please explain the inner workings of the following code:
System.out.println(new String("ABC").intern()==new String("ABC").intern());
In the above code it prints "true". But according java rules, in the case of the new operator, it always creates a new object. object.intern() method also creates an object in the string pool. So my question is, in the above code how many objects are created.
According to me, 3 new objects will created. One goes to String pool, and two anonymous objects will be created by the new operator. But i am not sure.
If i am wrong please explain.
Assuming no cleverness in the optimizer, two objects are created. (A smart enough optimizer could optimize this to just an unconditional true, in which case no objects are created.)
tl;dr version: You were almost right with your answer of 3, except that the string that goes into the String pool is not generated as part of this statement; it's already created.
First, let's get the "ABC" literal out of the way. It's represented in the runtime as a String object, but that lives in pergen and was created once in the whole life of the JVM. If this is the first class that uses that string literal, it was created at class load time (see JLS 12.5, which states that the String was created when the class was loaded, unless it previously existed).
So, the first new String("ABC") creates one String, which simply copies the reference (but does not create a new object) to the chars array and hash from the String that represents the "ABC" literal (which, again, is not created as part of this line). The .intern() method then looks to see whether an equal String is already in permgen. It is (it's just the String that represents the literal to begin with), so that's what that function returns. So, new String("ABC").intern() == "ABC". See JLS 3.10.5, and in particular:
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.
The same thing exactly happens with the second occurrence of new String("ABC").intern(). And, since both intern() method return the same object as the "ABC" literal, they represent the same value.
Breaking it down a bit:
String a = new String("ABC"); // a != "ABC"
String aInterned = a.intern(); // aInterned == "ABC"
String b = new String("ABC"); // b != "ABC"
String bInterned = b.intern(); // bInterned == "ABC"
System.out.println(new String("ABC").intern()==new String("ABC").intern());
// ... is equivalent to...
System.out.println(aInterned == bInterned); // ...which is equivalent to...
System.out.println("ABC" == "ABC"); // ...which is always true.
When you call intern() method, jvm will check if the given string is there, in string pool or not. If it is there, it will return a reference to that, otherwise it will create a new string in pool and return reference to that.
In your case : System.out.println(new String("ABC").intern()==new String("ABC").intern());
The first new String("ABC").intern() will create a string "ABC" in pool.When you call new String("ABC").intern() second time, jvm will return the reference to previously created string.That is the reason you are getting true when comparing both(btn are pointing to same reference).
I believe you are right, as new operation create a new object so there are 2 anonymous objects and intern() creates a new string in the string pool only if it is not already and returns it's reference
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
String comparison and String interning in Java
I have small doubt regarding String comparisons in Java, consider the following code:
if("String".replace('t','T') == "String".replace('t','T')) {
System.out.println("true");
}
else {
System.out.println("false");
}
The above code always print's false, where as if I try like this:
if("STring" == "STring") {
System.out.println("true");
}
else {
System.out.println("false");
}
It will always print me true. Yes, I know String comparisons should be done with String.equals() or equalsIgnoreCase() method. But this is one of the question was asked in interview and I am confused. Can anyone guide me on this behavior?
As per my knowledge, in code snippet 1, "String.replace('t','T') is returning object, so object comparisons returns in false. Am I right?
"String.replace('t','T') is returning object, so object comparisons
returns in false. Am I right?
Yes, as for this case, you are right. String#replace(or any method of String class for that matter), will return a new String object (You can guess why? Immutability). And thus you would have to do the comparison using equals method, to compare their contents.
Now, in the second case: -
"STring" == "STring"
You are comparing two string literals. Now, since String literals are interned in Java, so both the literals are same (in the sense, they point to the same memory location), and hence == comparison gives you true.
The difference in comparison using == and equals is that, == compares the reference value - i.e value of memory location of objects, which will be different for two different string objects, as you are having in first case. Whereas, equals compares the actual content in those objects.
"String.replace('t','T') is returning object, so object comparisons
returns in false. Am I right?
Yes, == compares object references, and your first code is comparing two different objects.
As far as the second code is concerned its due to string interning.
ok lets do it like this, your both String objects "String" are referering to the same object.
So they are "basicly" equal. That is a thing the compiler does for you
but the method replace, does create and return a new String object, and that is why your second code is not equal.
Java always compares the basic types (int, byte, etc) or references for objects when using ==.
The java compiler optimizes the two string constants you entered to use the same object, thus the same reference, thus the == return true
DO this way
("String".replace('t','T').Tostring() == ("String".replace('t','T')).ToString()
This will solve your problem because the replace statement should be converted to string before eveluation.
You can also user the String.Equals for this or better you use ignore case as you mention in your question.
Try this:
if(string1.equals(string2)){
...
}