String concatenation: + operator with String literal - java

why s3==s4 returns false while s2==s3 returns true in line no. 8 and 7 respectively.
1. String s="hello";`
2. String s1="he"+"llo";
3. String s2="hello"+123;
4. String s3="hello123";
5. String s4=ss+"123";
7. System.out.println(s==s1);//prints true
8. System.out.println(s2==s3);//prints true
9. System.out.println(s3==s4);//prints false

s + "123"; is not compile-time evaluable so is not a candidate for string internment. (Note that if s was final then it would be.)
Therefore its reference will not be the same as s3, so the output is false.
The others all compare true due to string internment and the compile-time evaluabality of the expressions.

When you use == operator to check the equality of Strings, it checks if the location of the Strings in the memory is the same.
In cases 2 and 4, the Strings "hello" and "hello123" will already be in the String Constant Pool (due to lines 1 and 3) and will be recognized as equivalent to those Strings, and will use the same place in memory for each. In simple terms, it will create a String object and plug it into both instances of "hello" and "hello123".
When you do:
String s4=s+"123";
At run time, it creates a new memory location for s4, since, the JLS says that:
Strings computed by concatenation at run-time are newly created and therefore distinct.
So, the memory locations are different, and hence it gives false as the output.

Related

Difference between concatenation at run time and compile time in java

public class First
{
public static void main(String[] args)
{
String str1="Hello ",str2="World",str3="Hello World";
System.out.println(str3==("Hello "+"World")); //Prints true
System.out.println(str3==("Hello "+str2)); //Prints false
}
}
The reason of the above is given in JLS-
• Strings computed by constant expressions (§15.28) are computed at
compile time and then treated as if they were literals.
• Strings computed by concatenation at run time are newly created and
therefore distinct.
What I wanted to ask is-
Why the strings which are computed at run time differ from those which are computed at compile time?
Is it because of the memory allocation,one is allocated memory in heap and one in String pool or there is some other reason?Please clarify.
The compiler can't know what str2 contains because it would have to execute the code to know the contents of str2 when you are concatenating it with "Hello " (it could make some optimizations and inline it, since it doesn't change, but it doesn't do it).
Imagine a more complex scenario where str2 is something that a user typed in. Even if the user had typed "World" there was no way the compiler could've known that.
Therefore, it can't perform the comparison str3 == "Hello World" using the same "Hello World" from the constant pool that's assigned to str3 and used in the first comparison.
So the compiler will generate the concatenation by using StringBuilder and will end up creating another String with value Hello World, so the identity comparison will fail because one object is the one from the constant pool and the other one is the one that was just created.
You should use equals when comparing Objects and not the == operator.
Strings are immutable in Java. So, when you concatenate two strings, a third one is created at runtime to represent the concatenated value. So using == returns false as both arguments are pointing to different instances of String object.
For compile time scenario, due to compiler optimization, the concatenated string is already created, and at runtime, boht arguments of == are being represented by same instances. Hence, == returns true as both arguments point to same instance (reference).
The compiler recognizes that constants won't change and if you are using the + operator, will concatenate them in the compiled code.
That's why in first case it will run the execution as str3==("HelloWorld") since "Helloworld" literal is already present in the string pool they both will point at the same location in the String pool it will print true .
In case of str3==("Hello"+str2),the compiler won't check that str2 has World in it, it will consider it as a variable that can have any value so at run time they will create a new string variable which point to different HelloWorld than the str3 in the string pool, so it will print false.

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.

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.

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