equals method in java - java

I have read about the equals() method in java. I've heard that it compares based just on value. But then why is it returning false for my case below where the value is the same but the types are different?
public class test {
public static void main(String[] args)
{
String s1="compare";
StringBuffer s2=new StringBuffer("compare");
System.out.println(s1.equals(s2)); //false
}
}

A String instance cannot be equal to a StringBuffer instance.
Look at the implementation :
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) { // this condition will be false in your case
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
In theory you can have an equals implementation that may return true when comparing two objects not of the same class (not in the String class though), but I can't think of a situation where such an implementation would make sense.

String is different from StringBuffer. Use toString() to convert it to a String.
String s1="compare";
StringBuffer s2=new StringBuffer("compare");
System.out.println(s1.equals(s2.toString()));

Yes Eran is right you can't compair two diffrent objects using equals . If you really wants to do that then use toString() on StringBuffer
System.out.println(s1.equals(s2.toString()));

The equals() method belongs to Object.
From the Java docs for Object
Indicates whether some other object is "equal to" this one.
So basically:
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x
and y refer to the same object (x == y has the value true).
If you have a String and a StringBuffer they would not be equal to each other.
They might have the same value, but they aren't equal, have a look at the instanceOf() method.

Related

.equals() when class constructor is created & comparing of simple string

I had made a program on .equals() in java & having some conceptual problem when I saw some of the online videos on youtube & searched about this thing but not got proper explanation. So guys help me with that thing.
Thanks.
package Practice;
public class StringManipulation11 {
StringManipulation11(String s) {
}
public static void main(String[] args) {
String s = "Good";
String s1 = "Good";
String s2 = "Morning";
String t = new String("Good");
String t1 = new String("Good");
String t2 = new String("Morning");
StringManipulation11 sm = new StringManipulation11("Good");
StringManipulation11 sm1 = new StringManipulation11("Good");
System.out.println(s.equals(s1));// true because check content
System.out.println(s.equals(s2));// false content not match
System.out.println(t.equals(t1));// true because check content
System.out.println(s.equals(t));// true because check content
System.out.println(sm.equals(sm1));// false, but not getting the reason
// why it is false
/*
* In this case also the content is same but not getting the proper
* conclusion why it is false & it is false then why i am getting true
* in "System.out.println(t.equals(t1))" in this condtion.
*/
System.out.println(s.equals(sm));
}
}
In this case, also the content is same but not getting the proper conclusion why it is false & it is false then why I am getting true in System.out.println(t.equals(t1)) in this condition.
The class String has an implementation of equals (and hashcode) which compares the two objects character by character. Your class does not have an implementation of these methods, so it uses the implementation it has inherited from Object, which compares the references, i.e. for it to be true, the instances need to be the same.
That's an important distinction to get your head around, same means these two references are pointing to the exact same instance. And equals means that they are either the same or have equivalent content, but it is up to you to define how the content is compared, see this.
StringManipulation11 is extend object, if you didn't override the equals method the default method is
public boolean equals(Object obj) {
return (this == obj);
}
you can compare the equals method in String
public boolean equals(Object var1) {
if(this == var1) {
return true;
} else {
if(var1 instanceof String) {
String var2 = (String)var1;
int var3 = this.value.length;
if(var3 == var2.value.length) {
char[] var4 = this.value;
char[] var5 = var2.value;
for(int var6 = 0; var3-- != 0; ++var6) {
if(var4[var6] != var5[var6]) {
return false;
}
}
return true;
}
}
return false;
}
}
This is the definition of the equals method in the String class (Java 8):
public boolean equals(Object anObject)
Compares this string to the specified object. The result is true if and only
if the argument is not null and is a String object that represents the same
sequence of characters as this object.
Which means that this method returns true if and only if both Strings represent the same sequence of characters.
In your case you have defined a new class StringManipulation11 which by default uses the equals method of the Object class. And this is its definition:
The equals method for class Object implements the most discriminating
possible equivalence relation on objects; that is, for any non-null
reference values x and y, this method returns true if and only if x and y
refer to the same object (x == y has the value true).
In your example you have defined two different objects sm and sm1. These variables refer to DIFFERENT objects and this is why the equals method returns false.

Java string comparison not working as intended

I've done quite a bit of string comparisons in java in the past, but this time it doesn't seem to work.
I'm aware of the fact, that you have to use the .equals() function in order to compare strings in java.
In my attempt to figure out what's wrong, I wrote the following code snippet: Log.e("testLogic", String.valueOf(taken.getText().toString().trim().equals('1')));
Log.e("testValue", taken.getText().toString().trim());
producing the following result:
E/testLogic﹕ false
E/testValue﹕ 1
E/testLogic﹕ false
E/testValue﹕ 1
E/testLogic﹕ false
E/testValue﹕ 0
This seems rather strange, since the two first 'testLogic' logs should produce true.
The code is used in a custom list adapter if it means anything.
/Mikkel
It is because you are not comparing 2 Strings. You have to put it like this:
Log.e("testLogic", String.valueOf(taken.getText().toString().trim().equals("1")));
because .equals() function needs two Strings. Supposing that s1 and s2 are Strings, you should do:
s1.equals(s2);
I expect it will be helpful for you!
The .equals() comes from the Object class. Each class inherit it from the Object class. String class also inherited it from the Object class and override it like this -
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
And String has not any overloaded version of equals method for char. You can see if String's .equals() method takes any object but it returns false when it is any type rather than String. It only returns true if the provided parameter is of type String and is meaningfully equals. So you have to write -
Log.e("testLogic",String.valueOf(taken.getText().toString().trim().equals("1")));
instead of -
Log.e("testLogic", String.valueOf(taken.getText().toString().trim().equals('1')));

Enterring meaningfully equal data to a HashSet

Friends, I found a question like this in HashSets.
public class _235 {
private String s;
public _235(String s){
this.s=s;
}
public static void main(String[] args){
HashSet<Object> hs=new HashSet<Object>();
_235 ws1=new _235("ABC");
_235 ws2=new _235("ABC");
String s1=new String("ABC");
String s2=new String("ABC");
hs.add(ws1);
hs.add(ws2);
hs.add(s1);
hs.add(s2);
System.out.println(hs.size());
}
}
When I checked both ws1 and ws1 have added to the HashSet but not from s1 and s2 only one String has added. Since w1 and w2 have not gone through equal() I believe HashSet doesn't recognize them as equal 2 objects. But why doesn't this become same for Strings s1 and s2 as well. How it hs been identified they are as meaningfully equal objects. Please kindly explain.
HashSet requires your custom class to override equals() and hashcode() methods which are used internally to detect duplicate elements.
String class has this implementation but your custom class _235 does not have one.
Note: It is important to override both equals() and hashcode() and not just one of them or else results could be unpredictable when used with hash-based collections.
You must override hashCode() in every class that overrides equals().
Failure to do so will result in a violation of the general contract
for Object.hashCode(), which will prevent your class from functioning
properly in conjunction with all hash-based collections, including
HashMap, HashSet, and Hashtable.
from Effective Java, by Joshua Bloch
Here is a link with good explanation.
First of all String has overridden its equals method that checks for the content of it not through hashCode so when you add in the parameter of String "ABC" and other one "ABC" it will return true if the contents are the same.
String equals method:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}
While on objects they only used the default equals method which use the hashCode of the object
Object equals method:
public boolean equals(Object obj) {
return (this == obj);
}
In your result:
the wsi and ws2 will always return false when executing equals method because they are located on different memory location while the s1 and s2 will return true when they have the same content thus only adding one instance of it to the HashSet, that HashSet does not allowed duplicates.

Two objects with same data are not the same?

I have a test class like so:
public class CompareObjects {
public static class Obj {
public int i;
public Obj(int i) {
this.i = i;
}
}
public static void main(String[] args) {
Obj o1 = new Obj(0);
Obj o2 = new Obj(0);
if(o1 == o2) {
System.out.println("Equal");
}else{
System.out.println("Not equal");
}
}
}
I though the test would return "Equal", but it didn't. Why doesn't Java consider two objects with equal components not the same? Am I doing something wrong here? I have a feeling I completely overlooked something when I started learning Java.
Also, I tested the two against each other with the equals() method, and I get the same result. My reason for this question is that I would like to be able to test an ArrayList with the contains() method to see if one object has the same components as another and therefore equal. Any ideas?
== compares the references to the object. For example:
Obj a = new Obj(0);
Obj b = a;
//a == b
Try implementing equals():
public static class Obj {
public int i;
public Obj(int i) {
this.i = i;
}
#Override
public boolean equals(Object other) {
if (other == this) return true;
if (!(other instanceof Obj) || other == null) return false;
return i == ((Obj)other).i;
}
#Override
public int hashCode() {
return i;
}
}
Then, you can use if(o1.equals(o2)) {. However, this is not really a good example, read this (link) for more information.
== returns true only if you are comparing the same object [i.e. the same memory location].
If you want to compare objects by their fields, you have to overload the equals() method, in order to induce an equivalence relation over them.
public boolean equals(Object other){
return this.i == other.i;
}
Be sure that the equals() method respects reflexivity, symmmetry, transitivity.
== compares the reference equality, i.e if they refer to the same object in the memory.
You need to override equals() method, and use it whenever you want to compare their values. Also, override hashCode() which is used by HashMap for example.
The == operator does not check for equality in class data; rather, it checks to see if they are the same location in memory. If you did o2 = o1 instead of initializing them the same way, they would be the same location in memory, so o2==o1 would return true. However, since they were initialized some separately, it returns false. Instead, you should define an equals method and implement that.

Difference between String#equals and String#contentEquals methods

What is the difference between the String#equals method and the String#contentEquals method?
The String#equals() not only compares the String's contents, but also checks if the other object is also an instance of a String. The String#contentEquals() only compares the contents (the character sequence) and does not check if the other object is also an instance of String. It can be anything as long as it is an implementation of CharSequence which covers a.o. String, StringBuilder, StringBuffer, CharBuffer, etc.
To put it easily: String.contentEquals() is the smarter brother of String.equals(), because it can be more free in the implementation than String.equals().
There are some reasons why there is a separate String.contentEquals() method. The most important reason I think is:
The equals method has to be reflexive. That means that: x.equals(y) == y.equals(x). This implies that aString.equals(aStringBuffer) would have to be the same as aStringBuffer.equals(aString). This would require the Java API developers to make some special implementation for Strings in the equals() method of StringBuffer, StringBuilder and CharSequence as well. This would be a mess.
This is where String.contentEquals comes in. This is a standalone method that does not have to follow the strict requirements and rules for Object.equals. This way, you can implement the sense of "equal content" more freely. This allows you to make intelligent comparisons between a StringBuffer and a String, for example.
And to say what exactly the difference is:
String.contentEquals() can compare the contents of a String, a StringBuilder, a StringBuffer, a CharSequence and all derived classes of these. If the parameter is of type String, then String.equals() get executed.
String.equals() only compares String objects. All other object types are considered as not equal.
String.contentEquals() can compare StringBuffer and StringBuilder in an intelligent way. It does not call the heavy toString() method, which copies the whole content to a new String object. Instead, it compares with the underlying char[] array, which is great.
This answer was already posted by dbw but he deleted it but he had some very valid points for the difference while comparing execution time, what exceptions are thrown,
If you look at the source code String#equals and String#contentEquals it is clear that there are two overridden methods for String#contentEquals one which take StringBuilder and other CharSequence.
The difference between them,
String#contentEquals will throw NPE if the argument supplied is null but String#equals will return false
String#equals compares the content only when the argument supplied is instance of String otherwise it will return false in all other cases but on the other hand String#contentEquals checks the content of all the objects which implement interface CharSequence.
You can also tweak the code so that String#contentEquals return the wrong result or result you want by overriding equals method of the argument passed as shown below but you can not do those tweaks with String#equals.
Below code will always produce true as long as s contains any string which is 3 character long
String s= new String("abc");// "abc";
System.out.println(s.contentEquals(new CharSequence()
{
#Override
public CharSequence subSequence(int arg0, int arg1) {
// TODO Auto-generated method stub
return null;
}
#Override
public int length() {
// TODO Auto-generated method stub
return 0;
}
#Override
public char charAt(int arg0) {
// TODO Auto-generated method stub
return 0;
}
#Override
public boolean equals(Object obj)
{
return true;
}
}));
String#contentEquals will be slower then String#Equals in the case when argument supplied is instance of String and the length of both String is same but contents are not equal.
Example if the string are String s = "madam" and String argPassed = "madan" then s.contentEquals(argPassed) will take almost double execution time in this case as compared to s.equals(argPassed)
If the content length are not same for both the strings then function String#contentEquals will have better performance then String#Equals in almost all possible cases.
One more point to add to his answer
String#contentEquals of a String object will also compare to the StringBuilder contents and provide the appropriate result while String#Equals will return false
String class equals(Object o) method does only String comparison. But contentEquals(CharSequence cs) checks for classes extends AbstractStringBuilder i.e. StringBuffer, StringBuilder and String class also (They all are of type CharSequence).
String str = "stackoverflow";
StringBuilder builder = new StringBuilder(str);
System.out.println(str.equals(builder));
System.out.println(str.contentEquals(builder));
output:
false
true
The output of first stmt is false because builder is not of type String so equals() returns false but the contentEquals() checks for the content of all the type like StringBuilder, StringBuffer, String and as the content is same hence true.
contentEquals will throw NullPointerException if the argument supplied is null but equals() will return false because the equals() checks for instanceOf ( if (anObject instance of String) ) which returns false if the argument is null.
contentEquals(CharSequence cs):
Lets you check equality of given string value with any implementation instance of interface java.lang.CharacterSequence (eg, CharBuffer, Segment, String, StringBuffer, StringBuilder )
equals(Object anObject):
Lets you check equality of given string value with any instance of type java.lang.String only
RTFC :)
Since reading the source is the best way to understand it, I am sharing the implementations of both the methods (as of jdk 1.7.0_45)
public boolean contentEquals(CharSequence cs) {
if (value.length != cs.length())
return false;
// Argument is a StringBuffer, StringBuilder
if (cs instanceof AbstractStringBuilder) {
char v1[] = value;
char v2[] = ((AbstractStringBuilder) cs).getValue();
int i = 0;
int n = value.length;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
// Argument is a String
if (cs.equals(this))
return true;
// Argument is a generic CharSequence
char v1[] = value;
int i = 0;
int n = value.length;
while (n-- != 0) {
if (v1[i] != cs.charAt(i))
return false;
i++;
}
return true;
}
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
There is another method of String#contentEquals():
public boolean contentEquals(StringBuffer sb) {
synchronized(sb) {
return contentEquals((CharSequence)sb);
}
}
equals() and contentEquals() are two methods in String class to compare two strings and string with StringBuffer.
The parameters of contentEquals() are StringBuffer and String(charSequence). equals() is used to compare two strings and contentEquals() is used to compare the contents of String and StringBuffer.
Method contentEquals and equals are
public boolean contentEquals(java.lang.StringBuffer);
public boolean contentEquals(java.lang.CharSequence);
public boolean equals(Object o)
Here is an code which describes both methods
public class compareString {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "hello";
StringBuffer sb1 = new StringBuffer("hello");
StringBuffer sb2 = new StringBuffer("world");
boolean result1 = str1.equals(str2); // works nice and returns true
System.out.println(" str1.equals(str2) - "+ result1);
boolean result2 = str1.equals(sb1); // works nice and returns false
System.out.println(" str1.equals(sb1) - "+ result2);
boolean result3 = str1.contentEquals(sb1); // works nice and returns true
System.out.println(" str1.contentEquals(sb1) - "+ result3);
boolean result4 = str1.contentEquals(sb2); // works nice and returns false
System.out.println(" str1.contentEquals(sb2) - "+ result4);
boolean result5 = str1.contentEquals(str2); // works nice and returns true
System.out.println(" str1.contentEquals(str2) - "+ result5);
}
}
Output:
str1.equals(str2) - true
str1.equals(sb1) - false
str1.contentEquals(sb1) - true
str1.contentEquals(sb2) - false
str1.contentEquals(str2) - true
The contentEquals() method checks is the contents are same between a String, StringBuffer, etc which some kind of char sequence.
String#equals takes Object as an argument and checks it is instance of String object or not. If the argument object is String Object then it compares content character by character. It returns true in case content of both string objects are same.
String#contentEquals takes CharSequence interface as an argument. CharSequence can be implements in 2 ways-by using i) String class or (ii) AbstractStringBuilder( parent class of StringBuffer, StringBuilder)
In contentEquals() length is compared before any object instance check. If length is same then it checks argument object is instance of AbstractStringBuilder or not. If it is so(i.e. StringBuffer or StringBuilder ) then content is checked character by character. In case argument is an instance of String object then String#equals called from String#contentEquals.
So in short,
String#equals compares the content character by character in case argument is String object also. And String#contentEquals compares the content in case argument object implement CharSequence interface.
String#contentEquals is slower in case we compare two same length string content as String#contentEquals internally calls String#equals for String object.
In case we try to compare objects with difference content length (say "abc" with "abcd") then String#contentEquals is faster than String#equals. Because length is compared before any object instance checking.
BTW, the historical reason for the difference is that String originally had no superclass, so String.equals() takes a String as its argument. When CharSequence was introduced as the superclass of String, it needed an equality test of its own that worked across all CharSequence implementations, and that would not collide with the equals() already in use by String... so we got CharSequence.contentEquals(), which is inherited by String.
If CharSequence has been present in Java 1.0, we would probalby have only CharSequence.equals() and String would simply implement that.
Ah, the joys of evolving languages...

Categories