Java substring.equals versus == - java

Using the standard loop, I compared a substring to a string value like this:
if (str.substring(i, i+3) == "dog" ) dogcount++;
and it broke the iteration. After the first increment, no further instances of "dog" would be detected.
So I used substring.equals, and that worked:
if (str.substring(i, i+3).equals("dog")) dogcount++;
My question is, why? Just seeking better understand, thx.

You should use equals() instead of == to compare two strings.
s1 == s2 returns true if both strings point to the same object in memory. This is a common beginners mistake and is usually not what you want.
s1.equals(s2) returns true if both strings are physically equal (i.e. they contain the same characters).

== compares references. You want to compare values using equals() instead.

For String comparison, always use equals() method. Because comparing on == compares the references.
Here's the link for further knowledge.
You might also want to read this for understanding difference between == and equals() method in a better way along with code examples.

== compares references(storage location of strings) of strings
and
.equals() compares value of strings

"String" is an object in Java, so "==" compares the references, as stated.
However, code like
String str1 = "dog";
String str2 = "dog";
if(str1==str2)
System.out.println("Equal!");
will actually print out "Equal!", which might get you confused. The reason is that JVM optimizes your code a little bit when you assign literals directly to String objects, so that str1 and str2 actually reference the same object, which is stored in the internal pool inside JVM. On the other hand, code
String str1 = new String("dog");
String str2 = new String("dog");
if(str1==str2)
System.out.println("Equal!");
will print out nothing, because you explicitly stated that you want two new objects.
If you want to avoid complications and unexpected errors, simply never use "==" with strings.

Related

How == returns false even though two Strings s1 and s3 having same hashcode? [duplicate]

This question already has answers here:
two unequal objects with same hashcode
(9 answers)
Closed 6 years ago.
public static void main(String[] args) {
String str1 = "java";
String str2 = str1.intern();
String str3 = new String(str1.intern());
System.out.println("hash1=" + str1.hashCode());
System.out.println("hash2=" + str2.hashCode());
System.out.println("hash3=" + str3.hashCode());
System.out.println("str1==str2==>>" + (str1 == str2));
System.out.println("str1==str3==>>" + (str1 == str3));
}
============================================output===>
hash1=3254818
hash2=3254818
hash3=3254818
str1==str2==>>true
str1==str3==>>false
=================================
Can anyone explain how == returns false even though s1 and s3 having same hashcode?
Despite the comments above, I suspect that you already understand that == determines if two references point to the same object (or are both null), and that you should use equals() if you want to compare two strings for data-equality.
Rather, I think what you're missing is that the hashCode() method corresponds to the equals() method in this respect; it's based on the data in an object, and in fact, it's specified that classes should always implement hashCode() in such a way that if a.equals(b), then a.hashCode() == b.hashCode(). (Of course, there's nothing in the language that enforces this.) The analogue of == that you're looking for is the System.identityHashCode() method.
However, even there it should be noted that System.identityHashCode() does not guarantee that distinct instances will have distinct identity hash codes. (It can't, because it's possible to have more than 232 objects in a JVM at the same time . . . granted, not all JVMs support that; but nothing in the Java language specification forbids it.)
In a correct implementation of equals and hashCode you have the following implications for two objects a and b (that are not null):
if a == b then also a.equals(b)
if a.equals(b) then also a.hashCode() == b.hashCode()
Both implications cannot be reversed in general.
For two Objects the == operator compares their pointer reference. So unless they are actually the exact same object it's never true.
When you do:
String a = "xyz"
while creating the string, the JVM searches in the pool of strings if there already exists a string value xyz, if so 'a' will simply be a reference of that string and no new String object is created.
But if you say:
String a = new String("xyz")
you force JVM to create a new String reference, even if "xyz" is in its pool.
and == compares the references. That's why you are getting the false result.

How JVM allocates memory for String in java?

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.

Difference in string comparison result b/w == and String#replace with == [duplicate]

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)){
...
}

Weird Java Behaviour in string comparison [duplicate]

This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Java string comparison?
I have encounter the following problem, I have an object called "lang", is a result from a method LanguageDetector.detect() which output a string.
lang = LanguageDetector.detect();
So I would want to check whether the language is english, so I am checking,
lang == "en"
The following screen is my debug screen, my lang is showing "en", however my lang == "en" is showing false and lang.toString() == "en" is false, does anyone encounter following problem before and have a possible solution?
Use equals() method of String object instead of direct comparison.
String first = new String("Hello");
String second = new String("Hello");
first == second will return false.
first.equals(second) will return true.
In Java, == always does a reference comparison. You need a value comparison though (with the equals() method for instance).
You're comparing the references to the Strings rather than the contents of the strings themselves. See here for more info.
Note that this issue doesn't apply just to Strings, but to all objects. As such, you may have to define appropriate equals() methods for any objects you create yourself.
Additionally String interning will confuse matters if you're not careful. See here for more details.
Use lang.equals("en") instead of lang == "en". The latter compares the two string references for equality, whereas the former compares the contents of the two strings.
See http://www.devdaily.com/java/edu/qanda/pjqa00001.shtml for an overview of different string comparison methods in Java.
By using == you are checking that both string references point to the same object.
For strings that are created on the fly, and not interned, this will equal false.
To compare the strings for equality, letter by letter, use string1.equals(string2) or even string1.equalsIgnoreCase(string2).
Use "en".equals(lang) instead of lang == "en"
Its better to use the equals as said
but if its necessary for performance reasons you can try
the intern() function.
lang.intern() == "en"

Operator overloading in Java

Acordding to my knowledge in java I know, that there is no operator overloading in the Java language.
So, why this code prints 'true' twice ?
String s1 = "abc";
String s2 = "abc";
System.out.println(s1==s2);
Integer i1 = 1;
Integer i2 = 1;
System.out.println(i1==i2);
== for reference types compares the references; == for primitive types compares values. In case of your first example, the two object references turn out to be the same due to a concept known as string pool. Hence two true in the given case. Another code snippet you might want to try out:
String s1 = "abc";
String s2 = new String("abc");
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
As you must have already tried out; it prints out false and then true. The reason for this is that using the new keyword results in the creation of a completely new string even though a string object with the exact same contents already exists in the string pool. In this case, s1 now points to an interned string with the contents "abc" (or to a string in the string pool) whereas s2 now points to a completely new string object (again with the content "abc"). Hence the false in the first print statement.
In the second print statement, what we are doing is comparing the contents of the String object rather than its reference, which as it should prints true.
This is one of the most common mistakes made by beginners of the Java language; they use == for logical comparison when it actually results in a reference comparison. Read the link posted in one of the answers here for more details about string pooling. On a related note, String class "overrides" the equals method of the Object class to provide a logical comparison. Unless the class you write doesn't provide a logical implementation of the equals method, it doesn't matter whether you call equals or use the == operator; the result would be the same i.e. reference comparison.
For a more in-depth view on equality, read Brian's article; an excellent read.
It's not entirely true that there is no operator-overloading in Java. There just isn't any custom operator overloading. For example there's some operator-overloading with + which adds as both addition and as String-concatenation. This is defined by the language and can't be modified by the developer.
Your example, however doesn't use operator overloading anywhere. == on reference types always does the same thing: return true when the left side and the right side refer to the exact same object.
In this case s1 and s2 reference the same object and i1 and i2 reference the same object as well.
s1 and s2 reference the same interned String, because string literals are guaranteed to be interned.
i1 and i2 reference the same cached Integer because auto-boxing will re-use a fixed pool of Integer objects for common numeric values.
You don't get to overload operators, but that doesn't mean that it's not built into the JVM itself. The obvious counter example is the plus operator and the different behavior for String and numbers.
This is because "All literal strings and string-valued constant expressions are interned."
See http://download.oracle.com/javase/6/docs/api/java/lang/String.html#intern%28%29
Your code shows like its was related to operator overloading, but, is not.
String "==" operator seems to be "overloded" with Integer "==" operator. As #Sanjay T. Sharma mentioned in a previous answer, in Java there are "reference" types, and "primitive" types, which handles different the "==" operator.
Strings in Java are "reference" types, and integers are "primitive" types. If you have use pointers and objects in other languages, you will find that in Java, a string variables, is really a pointer to an object, and using the "==" operator behaves different.

Categories

Resources