I have come across this question in a test:
class Hello {
public static void main(String[] args){
String hello = "Hello", lo = "lo";
System.out.println(hello == ("Hel" + "lo"));
System.out.println(hello == ("Hel" + lo));
System.out.println(hello == ("Hel" + lo).intern());
}
}
The output is:
true
false
true
Why is the second output false?
It prints 'false' because the concatenation of the String constant "Hel" and the String object 'lo' results in a seaparate, anonymous string object, with its own unique object reference. Thus, the "hello" String object and the concatenated string are different objects based on object reference (== operator, not by String value with String.equals()).
== compares the references of two sides.
Here, for hello == ("Hel"+lo), the references of two sides are not the same. So, it returns false.
For comparing values, use equals() method.
I think it Comparision Literal Problem.
It Works.
System.out.print((hello.equals("Hel"+lo)) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
I think it is because in the second output ("Hel" + lo) is no more in the string. The equality "==" operator compares object memory location and not characters of String.By default Java puts all string literal into string pool, but you can also put any string into pool by calling intern() method of java.lang.String class, like string created using new() operator.
Related
I wanted to change a code which was like
if("T".equalsIgnoreCase(bo.getSubjectType())) //method-1
to
if(String.valueOf('T').equalsIgnoreCase(bo.getSubjectType())) //method-2
So for that reason I wrote a sample code
String s1 = "T";
String s2 = "T";
char c1 = 'T';
char c2 = 'T';
System.out.println(String.valueOf(c1) == String.valueOf(c2)); // false
System.out.println(s1 == s2); // true
Which pretty much says String.valueOf(arg) produces a String literal and places it in constant pool. So my question is whether there would be any contrast in performance when we try to manipulate a String in non-constant pool and that in a constant pool - basically which one would be better approach method-1 or method-2?
if(String.valueOf('T').equalsIgnoreCase(bo.getSubjectType()))
There is no advantage whatsoever to writing it like this.
String.valueOf('T') will always return a new string, equal to "T", because the result of String.valueOf(char) (or any valueOf overload, for that matter) is not cached. There is no reason to keep on creating the same string over and over.
Plus, it's more verbose.
Just stick with method 1.
Method 2 is hard-readable and has no improvements at all.
String created using new operator operator, it always creates a new object in heap memory. String created using String literal may return an existing object from the String pool, if it already exists.
It will not return a String from the pool and creates a String using new operator (Oracle JDK 10 source):
/**
* Returns the string representation of the {#code char}
* argument.
*
* #param c a {#code char}.
* #return a string of length {#code 1} containing
* as its single character the argument {#code c}.
*/
public static String valueOf(char c) {
if (COMPACT_STRINGS && StringLatin1.canEncode(c)) {
return new String(StringLatin1.toBytes(c), LATIN1);
}
return new String(StringUTF16.toBytes(c), UTF16);
}
If you want to define a String constant and that always will be loaded from the pool, just create a:
public static final String T = "T";
From JLS about string literals and pools:
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
and the compilation unit:
package other;
public class Other {
public static String hello = "Hello";
}
produces the output:
true true true true false true
This example illustrates six points:
• Literal strings within the same class (§8 (Classes)) in
the same package (§7 (Packages)) represent references to the same
String object (§4.3.1).
• Literal strings within different classes in
the same package represent references to the same String object.
• Literal strings within different classes in different packages
likewise represent references to the same String object.
• 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.
• The result of explicitly interning a computed string is the same
string as any pre-existing literal string with the same contents.
This is a very basic question regarding String.
String str1 = "abc";
String str2 = "abc";
System.out.println("out put " + str1 == str2);
I was shocked when I executed the program. I got false.
According to me, string literals are shared between the String references if another string wants to point to the same String literal. JVM will check it in String pool first and if it is not there then it will create one and give the reference, otherwise it will be shared between multiple String references like in this case (according to me).
So if I go by my theory then it should have been returning true as both the String reference point to same String literal.
You need to do the following to check it correctly:-
System.out.println("out put " + (str1 == str2));
This will give you true as expected.
Your statement does "out put" + str1 and then tries to equate it with str2
You're right about the String behaviour. But, you forgot about operator precedence. First addition is executed, later equality.
So, in your case, firstly "out put " + str1 is executed, which gives "out put abc". Later this is compared to str2, which gives false.
You meant "out put " + (str1 == str2), which indeed gives true.
I came across this question in a Facebook group. I know I should be using equals() method but I want to know why this is happening
class Main
{
public static void main (String[] args)
{
String s1="abc:5";
String s2="abc:5";
System.out.println(s1==s2);
System.out.println("s1 == s2 " + s1==s2);
}
}
OUTPUT
true
false
This is due to operator precedence. '+' has a higher precedence than ==. You are actually comparing ("s1 == s2" + s1) to s2.
http://introcs.cs.princeton.edu/java/11precedence/
The confusion is in the order of operations. What is happening is that you're concatenating "s1 == s2 " and s1, then using == on that result and s2.
They are different objects, so false is printed (and "s1 == s2" is not printed). Put parentheses:
System.out.println("s1 == s2 " + (s1==s2));
This will print s1 == s2 true because both s1 and s2 refer to the same interned string literal, "abc:5".
Oh I just make some change in the code and get that + first doing "s1 == s2 s1" then == with s2 which is not true. New code
class Main
{
public static void main (String[] args)
{
String s1="abc:5";
String s2="abc:5";
System.out.println(s1==s2);
System.out.println("s1 == s2 " + (s1==s2));
System.out.println("s1 == s2 " + s1==s2);
}
}
OUTPUT
true
s1 == s2 true
false
this is easy to understand once you thought about it: the 2. println first adds "s1 == s2" and your string s1 and then compares it with s2, so it outputs false, because "s1 == s2abc:5" is not "abc:5"
It is adding the strings "s1 == s2 " + s1 and then computing whether that is equal to s2. It is not so it is printing false.
The Java Operator Precedence might help you here.
I think when using "==" the system will just check if the two things share the same location in the systems memory. However, if you use the ".equals" method the system will check if the two Strings share the same characters.
Your code
System.out.println(s1==s2);
System.out.println("s1 == s2 " + s1==s2);
Since s1 and s2 are the same String literals
`s1==s2` is true
Thus the code can be written as
System.out.println(true); => true
System.out.println("true" + s1==s2);
Now, "true" + s1==s2 is comprehended as ("true" + s1)==s2 due to higher precedence given to "+". Thus
"true"+s1 => trueabc:5 and
s2 => "abc:5"
Hence
System.out.println("true" + s1==s2); => false
I think its because of operator precedence of something like that, if you do System.out.println(""+(s1==s2));, it will print true.
The behavior of String literals is very confusing in the code below.
I can understand line 1, line 2, and line 3 are true, but why is line 4 false?
When I print the hashcode of both they are the same.
class Hello
{
public static void main(String[] args)
{
String hello = "Hello", lo = "lo";
System.out.print((Other1.hello == hello) + " "); //line 1
System.out.print((Other1.hello == "Hello") + " "); //line 2
System.out.print((hello == ("Hel"+"lo")) + " "); //line 3
System.out.print((hello == ("Hel"+lo)) + " "); //line 4
System.out.println(hello == ("Hel"+lo).intern()); //line 5
System.out.println(("Hel"+lo).hashCode()); //hashcode is 69609650 (machine depedent)
System.out.println("Hello".hashCode()); //hashcode is same WHY ??.
}
}
class Other1 { static String hello = "Hello"; }
I know that == checks for reference equality and check in the pool for literals. I know equals() is the right way. I want to understand the concept.
I already checked this question, but it doesn't explain clearly.
I would appreciate a complete explanation.
Every compile-time constant expression that is of type String will be put into the String pool.
Essentially that means: if the compiler can (easily) "calculate" the value of the String without running the program, then it will be put into the pool (the rules are slightly more complicated than that and have a few corner cases, see the link above for all the details).
That's true for all the Strings in lines 1-3.
"Hel"+lo is not a compile-time constant expression, because lo is a non-constant variable.
The hash codes are the same, because the hashCode of a String depends only on its content. That's required by the contract of equals() and hashCode().
Strings computed by concatenation at runtime are newly created and therefore distinct
here is a link to read: http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
String object can be created in the following ways:
String str = new String("abcd"); // Using the new operator
// str is assigned with "abcd" value at compile time.
String str="abcd"; // Using string literal
// str is assigned with "abcd" value at compile time.
String str="ab" + "cd"; // Using string constant expression.
// str is assigned with "abcd" value at compile time.
String str1 = "cd";
String str = "ab"+str1; // Using string expression.
// str is assigned with "abcd" value at run time only.
and Hashcode will be calculated only at runtime based on the contents of the String objects.
It's because the comipler in this instance is not smart enough to work out that it can burn in the same string literal.
Hashcode needs to always return the same value for strings that are equivelent (calling .equals on it returns true) so will return the same result.
Its because following code
("Hel"+lo)) + " "
is translated internally to
new StringBuilder("Helo").append(new String(lo)).append(new String(" ")).toString()
So you can see that entirely a new String instance is created with help of different String instances. That is why you get false as they point to different memory locations in heap
The hashCode doesn't have anything to do with an objects reference (The == check is a reference comparator). Its possible to have 2 objects where the hashCode returns the same value, the equals operator returns true, but == returns false. This is when they are 2 different objects, but with the same value.
I believe the reason line 4 is returning false is that it is a value computed at runtime, and thus is a different string instance, with a different reference.
String literals are saved in a special memory, if they are exactly the same, they are pointed to the same map of memory. If you don't create a literal String, a new object will be created so it won't point to that memory so the reference won't be the same.
The intern() method tells the virtual machine to put it into that shared, string literals map of memory so next time you do that literal, it'll search there and point it.
As you already know ... this is just because of reference ...when string comes from the pool it will have same refrence ...but when u do manuplations a new string with new refrence is generated ...
You can check this link for pooling concept
The difference between line number 3 and 4 are as follows.
•Strings computed by constant expressions 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.
The above reference is taken from java spec. Please let me know if you need more clarification.
http://docs.oracle.com/javase/specs/jls/se7/html/jls-3.html#jls-3.10.5
System.identityHashCode() would be returned by the default method hashCode(), this is typically implemented by converting the internal address of the object into an integer.
Finally I know the answer !
Read Java SE 8 specification section 15.21.3 Reference Equality Operators == and != (http://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.21.3)
While == may be used to compare references of type String, such an
equality test determines whether or not the two operands refer to the
same String object.
The result is false if the operands are distinct
String objects, even if they contain the same sequence of characters(§3.10.5). The contents of two strings s and t can be tested for
equality by the method invocation s.equals(t).
So the following code :
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
The expression ("Hel"+lo) in line 3, return the new Strings that computed by concatenation at run time.
*Strings computed by concatenation at run time are newly created and therefore distinct.
(http://docs.oracle.com/javase/specs/jls/se8/html/jls-3.html#d5e1634)
So the result of this code:
class Test {
public static void main(String[] args) {
String hello = "Hello";
String lo = "lo";
System.out.println((hello == ("Hel"+lo))); // line 3
}
}
would result:
false
Because,
the "Hello" object in this expression:
String hello = "Hello";
and ("Hel"+lo) object in this expression:
System.out.print((hello == ("Hel"+lo)) + " ");
is different, although :
*they both contain the same sequence character, which is "Hello".
*they both have the same hashCode.
*hello.equals(("Hel"+lo)) will return true.
This question already has answers here:
How do I compare strings in Java?
(23 answers)
Closed 9 years ago.
I have a situation of appending String. And i'm confused ..
public static void foo() {
String s = "str4";
String s1 = "str" + s.length();
System.out.println("(s==s1) = " + (s1 == s));
}
And
public static void bar() {
String s = "str4";
String s1 = "str" + "4";
System.out.println("(s==s1) = " + (s1 == s));
}
In 1st case it's returning 'false' but in 2nd case 'true'
As i understand in both cases 'str4' object is being created on the heap. So it should return true in both cases. But it's not.
Kindly someone help me out why it's so. ? Thanks.!
Use
s1.equals(s)
to compare strings, otherwise you compare references.
In second case it returns true because String s1 = "str" + "4"; would be optimized to String s1 = "str4"; and s and s1 would refer to the same String.
The == operator in Java only returns true if both references refer to the same object. If you are trying to compare two Strings for equivalent content, you must use the equals() method.
you need to use .equals() for this
.equals() // if you dont want to ignore case
.equalsIgnoreCase() // if you want to ignore case
== compare the references.
In the second case both strings are equal .So references are also equal.
String s = "str4";
String s1 = "str" + "4"; .//finally str4
Here s1 ans s2 contents are equal.So they have same reference.
In my own understanding :
"str" => String
"4" => String
However,
s.length() => int
With ==, memory locations are compared.
Using the first example, Java creates another String which is in another memory location other than the location of 's' because you are trying to do String + int = String.
The second example returns true because it is just the same memory location as your 's' only that the value is changed. String + String = Concatenated String
Since you are trying to compare if the two strings have the same characters inside but not necessarily the same location, then s.equals(s1) is the best solution.
However, should you want to test if both variables are pointing to the same object then == must be used because of its shallow comparison.