I'm using an ArrayList, and at one point in the program I'm using the contains method to check if a certain item is contained in the ArrayList. The ArrayList holds objects of type CharProfile, a custom class, and it's seeing if a char is contained within it.
So it's using the equals method in the contains method, I assume. So something like CharProfile.contains(char), but it's not working.
I overrode the equals method in CharProfile:
#Override
public boolean equals(Object o) {
if (this.character == (Character)o) {
return true;
}
else {
return false;
}
}
So it should be using my equals method when CharProfile is trying to use it, right? So why won't it work?
(In terms of "not working" I'm referring to the fact that contains always returns false.)
You are comparing a reference type using ==, which is wrong. You must use equals, with proper null-checks added.
But this is just the beginning. Your main problem is that you are trying to compare a CharProfile object to a Character object. You probably need this instead:
public boolean equals(Object o) {
return o instanceof CharProfile
&& this.character.equals((CharProfile)o).character;
}
This assumes that your character field is never null. If it can be null, you need to check that before dereferencing it, as well.
You are overriding equals such that it test for equality of reference, the default behavior of the operator ==
You need to use equals(). You can also make it a oneliner and be more explicit in your cast.
#Override
public boolean equals(Object o) {
return o instanceof Character && this.character.equals(Character.class.cast(o));
}
You have to use the equals() method and DO NOT forget to override the hashCode() method as well. They go hand in hand.
Some people don't know this, but if using eclipse you can right click choose Source-> and Generate hashCode() and equals()...
But, I suggest that you learn what they're for first before using this convenience.
For example, You have CharProfile as below.
List<CharProfile> list = new ArrayList<CharProfile>();
list.add(new CharProfile('a'));
list.add(new CharProfile('b'));
list.add(new CharProfile('c'));
When list.contains('a') is does, the JVM will not call Override equals() method of CharProfile.
For more clear;
public class Data {
public boolean equals(Object o) {
System.out.println("I am data");
return false;
}
}
When list.contains(new Data()) is does, the JVM will not call Override equals() method of Data.
Now, You will get message like I am data..
Related
I ran into an interesting (and very frustrating) issue with the equals() method today which caused what I thought to be a well tested class to crash and cause a bug that took me a very long time to track down.
Just for completeness, I wasn't using an IDE or debugger - just good old fashioned text editor and System.out's. Time was very limited and it was a school project.
Anyhow -
I was developing a basic shopping cart which could contain an ArrayList of Book objects. In order to implement the addBook(), removeBook(), and hasBook() methods of the Cart, I wanted to check if the Book already existed in the Cart. So off I go -
public boolean equals(Book b) {
... // More code here - null checks
if (b.getID() == this.getID()) return true;
else return false;
}
All works fine in testing. I create 6 objects and fill them with data. Do many adds, removes, has() operations on the Cart and everything works fine. I read that you can either have equals(TYPE var) or equals(Object o) { (CAST) var } but assumed that since it was working, it didn't matter too much.
Then I ran into a problem - I needed to create a Book object with only the ID in it from within the Book class. No other data would be entered into it. Basically the following:
public boolean hasBook(int i) {
Book b = new Book(i);
return hasBook(b);
}
public boolean hasBook(Book b) {
// .. more code here
return this.books.contains(b);
}
All of a sudden, the equals(Book b) method no longer works. This took a VERY long time to track down without a good debugger and assuming the Cart class was properly tested and correct. After swaapping the equals() method to the following:
public boolean equals(Object o) {
Book b = (Book) o;
... // The rest goes here
}
Everything began to work again. Is there a reason the method decided not to take the Book parameter even though it clearly was a Book object? The only difference seemed to be it was instantiated from within the same class, and only filled with one data member. I'm very very confused. Please, shed some light?
In Java, the equals() method that is inherited from Object is:
public boolean equals(Object other);
In other words, the parameter must be of type Object. This is called overriding; your method public boolean equals(Book other) does what is called overloading to the equals() method.
The ArrayList uses overridden equals() methods to compare contents (e.g. for its contains() and equals() methods), not overloaded ones. In most of your code, calling the one that didn't properly override Object's equals was fine, but not compatible with ArrayList.
So, not overriding the method correctly can cause problems.
I override equals the following everytime:
#Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof MyClass)) return false;
MyClass otherMyClass = (MyClass)other;
...test other properties here...
}
The use of the #Override annotation can help a ton with silly mistakes.
Use it whenever you think you are overriding a super class' or interface's method. That way, if you do it the wrong way, you will get a compile error.
If you use eclipse just go to the top menu
Source --> Generate equals() and
hashCode()
Slightly off-topic to your question, but it's probably worth mentioning anyway:
Commons Lang has got some excellent methods you can use in overriding equals and hashcode. Check out EqualsBuilder.reflectionEquals(...) and HashCodeBuilder.reflectionHashCode(...). Saved me plenty of headache in the past - although of course if you just want to do "equals" on ID it may not fit your circumstances.
I also agree that you should use the #Override annotation whenever you're overriding equals (or any other method).
Another fast solution that saves boilerplate code is Lombok EqualsAndHashCode annotation. It is easy, elegant and customizable. And does not depends on the IDE. For example;
import lombok.EqualsAndHashCode;
#EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{
private long errorNumber;
private int numberOfParameters;
private Level loggingLevel;
private String messageCode;
See the options avaliable to customize which fields to use in the equals. Lombok is avalaible in maven. Just add it with provided scope:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
in Android Studio is
alt + insert ---> equals and hashCode
Example:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Proveedor proveedor = (Proveedor) o;
return getId() == proveedor.getId();
}
#Override
public int hashCode() {
return getId();
}
Consider:
Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
the instanceOf statement is often used in implementation of equals.
This is a popular pitfall !
The problem is that using instanceOf violates the rule of symmetry:
(object1.equals(object2) == true) if and only if (object2.equals(object1))
if the first equals is true, and object2 is an instance of a subclass of
the class where obj1 belongs to, then the second equals will return false!
if the regarded class where ob1 belongs to is declared as final, then this
problem can not arise, but in general, you should test as follows:
this.getClass() != otherObject.getClass(); if not, return false, otherwise test
the fields to compare for equality!
recordId is property of the object
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Nai_record other = (Nai_record) obj;
if (recordId == null) {
if (other.recordId != null)
return false;
} else if (!recordId.equals(other.recordId))
return false;
return true;
}
I ran into an interesting (and very frustrating) issue with the equals() method today which caused what I thought to be a well tested class to crash and cause a bug that took me a very long time to track down.
Just for completeness, I wasn't using an IDE or debugger - just good old fashioned text editor and System.out's. Time was very limited and it was a school project.
Anyhow -
I was developing a basic shopping cart which could contain an ArrayList of Book objects. In order to implement the addBook(), removeBook(), and hasBook() methods of the Cart, I wanted to check if the Book already existed in the Cart. So off I go -
public boolean equals(Book b) {
... // More code here - null checks
if (b.getID() == this.getID()) return true;
else return false;
}
All works fine in testing. I create 6 objects and fill them with data. Do many adds, removes, has() operations on the Cart and everything works fine. I read that you can either have equals(TYPE var) or equals(Object o) { (CAST) var } but assumed that since it was working, it didn't matter too much.
Then I ran into a problem - I needed to create a Book object with only the ID in it from within the Book class. No other data would be entered into it. Basically the following:
public boolean hasBook(int i) {
Book b = new Book(i);
return hasBook(b);
}
public boolean hasBook(Book b) {
// .. more code here
return this.books.contains(b);
}
All of a sudden, the equals(Book b) method no longer works. This took a VERY long time to track down without a good debugger and assuming the Cart class was properly tested and correct. After swaapping the equals() method to the following:
public boolean equals(Object o) {
Book b = (Book) o;
... // The rest goes here
}
Everything began to work again. Is there a reason the method decided not to take the Book parameter even though it clearly was a Book object? The only difference seemed to be it was instantiated from within the same class, and only filled with one data member. I'm very very confused. Please, shed some light?
In Java, the equals() method that is inherited from Object is:
public boolean equals(Object other);
In other words, the parameter must be of type Object. This is called overriding; your method public boolean equals(Book other) does what is called overloading to the equals() method.
The ArrayList uses overridden equals() methods to compare contents (e.g. for its contains() and equals() methods), not overloaded ones. In most of your code, calling the one that didn't properly override Object's equals was fine, but not compatible with ArrayList.
So, not overriding the method correctly can cause problems.
I override equals the following everytime:
#Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof MyClass)) return false;
MyClass otherMyClass = (MyClass)other;
...test other properties here...
}
The use of the #Override annotation can help a ton with silly mistakes.
Use it whenever you think you are overriding a super class' or interface's method. That way, if you do it the wrong way, you will get a compile error.
If you use eclipse just go to the top menu
Source --> Generate equals() and
hashCode()
Slightly off-topic to your question, but it's probably worth mentioning anyway:
Commons Lang has got some excellent methods you can use in overriding equals and hashcode. Check out EqualsBuilder.reflectionEquals(...) and HashCodeBuilder.reflectionHashCode(...). Saved me plenty of headache in the past - although of course if you just want to do "equals" on ID it may not fit your circumstances.
I also agree that you should use the #Override annotation whenever you're overriding equals (or any other method).
Another fast solution that saves boilerplate code is Lombok EqualsAndHashCode annotation. It is easy, elegant and customizable. And does not depends on the IDE. For example;
import lombok.EqualsAndHashCode;
#EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{
private long errorNumber;
private int numberOfParameters;
private Level loggingLevel;
private String messageCode;
See the options avaliable to customize which fields to use in the equals. Lombok is avalaible in maven. Just add it with provided scope:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
in Android Studio is
alt + insert ---> equals and hashCode
Example:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Proveedor proveedor = (Proveedor) o;
return getId() == proveedor.getId();
}
#Override
public int hashCode() {
return getId();
}
Consider:
Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
the instanceOf statement is often used in implementation of equals.
This is a popular pitfall !
The problem is that using instanceOf violates the rule of symmetry:
(object1.equals(object2) == true) if and only if (object2.equals(object1))
if the first equals is true, and object2 is an instance of a subclass of
the class where obj1 belongs to, then the second equals will return false!
if the regarded class where ob1 belongs to is declared as final, then this
problem can not arise, but in general, you should test as follows:
this.getClass() != otherObject.getClass(); if not, return false, otherwise test
the fields to compare for equality!
recordId is property of the object
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Nai_record other = (Nai_record) obj;
if (recordId == null) {
if (other.recordId != null)
return false;
} else if (!recordId.equals(other.recordId))
return false;
return true;
}
I ran into an interesting (and very frustrating) issue with the equals() method today which caused what I thought to be a well tested class to crash and cause a bug that took me a very long time to track down.
Just for completeness, I wasn't using an IDE or debugger - just good old fashioned text editor and System.out's. Time was very limited and it was a school project.
Anyhow -
I was developing a basic shopping cart which could contain an ArrayList of Book objects. In order to implement the addBook(), removeBook(), and hasBook() methods of the Cart, I wanted to check if the Book already existed in the Cart. So off I go -
public boolean equals(Book b) {
... // More code here - null checks
if (b.getID() == this.getID()) return true;
else return false;
}
All works fine in testing. I create 6 objects and fill them with data. Do many adds, removes, has() operations on the Cart and everything works fine. I read that you can either have equals(TYPE var) or equals(Object o) { (CAST) var } but assumed that since it was working, it didn't matter too much.
Then I ran into a problem - I needed to create a Book object with only the ID in it from within the Book class. No other data would be entered into it. Basically the following:
public boolean hasBook(int i) {
Book b = new Book(i);
return hasBook(b);
}
public boolean hasBook(Book b) {
// .. more code here
return this.books.contains(b);
}
All of a sudden, the equals(Book b) method no longer works. This took a VERY long time to track down without a good debugger and assuming the Cart class was properly tested and correct. After swaapping the equals() method to the following:
public boolean equals(Object o) {
Book b = (Book) o;
... // The rest goes here
}
Everything began to work again. Is there a reason the method decided not to take the Book parameter even though it clearly was a Book object? The only difference seemed to be it was instantiated from within the same class, and only filled with one data member. I'm very very confused. Please, shed some light?
In Java, the equals() method that is inherited from Object is:
public boolean equals(Object other);
In other words, the parameter must be of type Object. This is called overriding; your method public boolean equals(Book other) does what is called overloading to the equals() method.
The ArrayList uses overridden equals() methods to compare contents (e.g. for its contains() and equals() methods), not overloaded ones. In most of your code, calling the one that didn't properly override Object's equals was fine, but not compatible with ArrayList.
So, not overriding the method correctly can cause problems.
I override equals the following everytime:
#Override
public boolean equals(Object other){
if (other == null) return false;
if (other == this) return true;
if (!(other instanceof MyClass)) return false;
MyClass otherMyClass = (MyClass)other;
...test other properties here...
}
The use of the #Override annotation can help a ton with silly mistakes.
Use it whenever you think you are overriding a super class' or interface's method. That way, if you do it the wrong way, you will get a compile error.
If you use eclipse just go to the top menu
Source --> Generate equals() and
hashCode()
Slightly off-topic to your question, but it's probably worth mentioning anyway:
Commons Lang has got some excellent methods you can use in overriding equals and hashcode. Check out EqualsBuilder.reflectionEquals(...) and HashCodeBuilder.reflectionHashCode(...). Saved me plenty of headache in the past - although of course if you just want to do "equals" on ID it may not fit your circumstances.
I also agree that you should use the #Override annotation whenever you're overriding equals (or any other method).
Another fast solution that saves boilerplate code is Lombok EqualsAndHashCode annotation. It is easy, elegant and customizable. And does not depends on the IDE. For example;
import lombok.EqualsAndHashCode;
#EqualsAndHashCode(of={"errorNumber","messageCode"}) // Will only use this fields to generate equals.
public class ErrorMessage{
private long errorNumber;
private int numberOfParameters;
private Level loggingLevel;
private String messageCode;
See the options avaliable to customize which fields to use in the equals. Lombok is avalaible in maven. Just add it with provided scope:
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.14.8</version>
<scope>provided</scope>
</dependency>
in Android Studio is
alt + insert ---> equals and hashCode
Example:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Proveedor proveedor = (Proveedor) o;
return getId() == proveedor.getId();
}
#Override
public int hashCode() {
return getId();
}
Consider:
Object obj = new Book();
obj.equals("hi");
// Oh noes! What happens now? Can't call it with a String that isn't a Book...
the instanceOf statement is often used in implementation of equals.
This is a popular pitfall !
The problem is that using instanceOf violates the rule of symmetry:
(object1.equals(object2) == true) if and only if (object2.equals(object1))
if the first equals is true, and object2 is an instance of a subclass of
the class where obj1 belongs to, then the second equals will return false!
if the regarded class where ob1 belongs to is declared as final, then this
problem can not arise, but in general, you should test as follows:
this.getClass() != otherObject.getClass(); if not, return false, otherwise test
the fields to compare for equality!
recordId is property of the object
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Nai_record other = (Nai_record) obj;
if (recordId == null) {
if (other.recordId != null)
return false;
} else if (!recordId.equals(other.recordId))
return false;
return true;
}
I have been reading a book called Thinking in Java on Java(I come from C background). I came across the following two set of codes
public class EqualsMethod {
public static void main(String[] args) {
Integer n1 = new Integer(47);
Integer n2 = new Integer(47);
System.out.println(n1.equals(n2));
}
}
//Output: true
I understand that this equal method is comparing the reference. But n1 and n2 are two object residing in ´two different "bubble" in the heap. So how come they are equal?
Another example code is
class Value {
int i;
}
public class EqualsMethod2 {
public static void main(String[] args) {
Value v1 = new Value();
Value v2 = new Value();
v1.i = v2.i = 100;
System.out.println(v1.equals(v2));
}
} /* Output:false
}
Why does this give false? Your in depth answer would be much anticipated. Thank you.
The behavior of equals in your custom classes is entirely up to you. If you override it, you decide when two objects of your class are considered equal to each other. If you don't override it, you get the default implementation of Object class, which checks if both references refer to the same object (i.e. checks if v1==v2 in your example, which is false).
Root of the issue :
You have not overrriden eqauals and hashCode and then JVM assigns a new hashCode to any object you create in the case of Value class
=================
Solution :
You will need to define the criteria on which the identities of the value object is measured i.e do the following
1) Override the equals method and specify that the equality is checked over the value of the instance variable i
2) Override Hashcode and use instance variable i for the hashCode comparison
== is used in the equals method in the object class to avoid unnecessary calculation if the two refrences point to the same object and if not go ahead with the calculation and comparisons
public boolean equals(Object anObject)
{
if (this == anObject) {
return true;
}
else{
// Do the calculation here to check the identity check
}
I understand that this equal method is comparing the reference.
Wrong. In the Object class, this method contains a referential comparison, but Integer has it's own implementation, which overrides the one provided by Object.
It compares the values of the two Integers, not their references.
Integer is valuable type. So comparing to Integer variables performing by comparing their values. Which are equal in your particular case.
Comparing two objects (reference type) performing by comparing the references, which are not equal.
You could write your own comparison logic by overloading the equals() method in your class.
Integer has the method equals() that compare the value, and your Value class doesn't. It makes the Value class with equals compare the "pointer", and they're different.
If you override the method equals in your class Value comparing the attribute i from the class, it would return true.
For example
public boolean equals(Object o){
return (this.i == ((Value) o).i) ? true : false;
}
Equals method in all Wrapper classes is overridden by default in java. That's is why first snippet works.
For your own classes, you have to provide an implementation of equals method.
By default the equal method in Java check if the two Object references are the same. You can #Override the method, and do what you want. So it is normal that you get False, because the two Object are different.
So how come they are equal?
Integer is an Object. On the other side int is a simple type.
Integer's equals() method compare int inside, because it's overriding Object equals() method. int's there has the same value.
Why does this give false?
Your Value class doesn't override equal's method, so then refferences are compared, exactly like when you write v1 == v2. In this case they are different Objects so it's false.
Because you have not override equals method. If you do not override it then it will check if the reference are equal or not and return accordingly.
You can refer equals() method defined in Integer class.
System.out.println(n1.equals(n2)) // this prints true because it refers to Integer equals method.
Similarly you will have to override it for your Value class like.
class Value {
int i;
#Override
public boolean equals(Object obj) {
boolean returnValue = false;
if (obj != null && obj instanceof Value) {
Value valObj = (Value) obj;
if (this.i == valObj.i) {
returnValue = true;
}
}
return returnValue;
}
}
Now System.out.println(v1.equals(v2)); prints true.
Hi your understanding of equals and == is completely wrong or opposite to what it actually is.
equals() method also checks for reference as == does, there is no difference between both of them unless you override the equals method.
== check for reference equality. For better understanding see Object class source code.
public boolean equals(Object obj) {
return (this == obj);
}
Why is it working in your case? is because Integer class overrides the equals method in it.
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
n
}
Now when you use your custom class to check equality what it is doing is basically calling.
v1==v2
How it can give you true? They both have different memory locations in heap.
If still things are not clear put break points in your code and run it in debug mode.
Hello I am trying to write a Java comparison which takes the current object called MovieCard and compares it with another MovieCard passed as a parameter. code below
boolean sameName(MovieCard movieCard) {
if(this.MovieCard.equals(movieCard))
return true;
}
error cannot find symbol - variable MovieCard
The check is listed in my class before the MovieCard constructor if this makes any difference. Also I'm in a beginner programming class so we cannot use Comparator and it needs to contain this.
boolean sameName(MovieCard movieCard) {
return this.equals(movieCard);
}
MovieCard is a class, not a variable. And that's what the compiler is telling you.
if(this.MovieCard.equals(movieCard))
↑
You probably have to write only this.
Also note that there exists a path that doesn't return anything, this won't compile.
You should do:
boolean sameName(MovieCard movieCard) {
return this.equals(movieCard);
}
Or
boolean sameName(MovieCard movieCard) {
if(this.equals(movieCard)) {
return true;
}
return false;
}
use like
boolean sameName(MovieCard movieCard) {
if(this.equals(movieCard))
return true;
}
But it seems your method is checking whether two object has same name. if so then you can simply use
boolean sameName(MovieCard movieCard) {
if(this.name.equals(movieCard.name))
return true;
}
assuming name is a member variable(string)
If this method is present in your MovieCard class, then just this would suffice.
boolean sameName(MovieCard movieCard) {
if(this.equals(movieCard)) {// this is enough. this.MovieCard is wrong, as there is no variable by that name.
return true;
}
return false; // Since return true is a conditional return, but the method needs to return in any case.
}
And a shortened version of your method would be
boolean sameName(MovieCard movieCard) {
return this.equals(movieCard); // Returns the result of the comparison.
}
If looking at the method name, sameName(), it looks like you want to compare some name field in the class, instead of the objects as such.
boolean sameName(MovieCard movieCard) {
return this.getName().equals(movieCard.getName()); // Returns the result of the name comparison.
// But there is a possible NPE in the above statement.
}
You have to write
boolean sameName(MovieCard movieCard) {
if (this.equals(movieCard)){
return true;
} else{
return false;
}
}
Because this.MovieCard points to a variable in your Moviecard class.
Besides your syntax error, Your equals implementation does nothing other that default implementation
Remember if (this.equals(movieCard)){ This is only true when the movieCard and this points to the same reference.
Because,
Default implementation of equals() class provided by java.lang.Object compares memory location and only return true if two reference variable are pointing to same memory location i.e. essentially they are same object.
I guess you need to override the equals method in your MovieCard class, Such that comparing the fields of MovieCard's are same or not.
Prefers to read, How to essentially Ovveride equals.
You are moving in a wrong direction, Please see the example in the above link and then implement equals
in such a way that If all the fields in MovieCard equals to the passed Object's fields. That would be the implementation you asked for.
In general an example for comparing two Tiger Object's for equals like this
#Override
public boolean equals(Object object) {
boolean result = false;
if (object == null || object.getClass() != getClass()) {
result = false;
} else {
Tiger tiger = (Tiger) object;
if (this.color == tiger.getColor() //checking color and pattern same
&& this.stripePattern == tiger.getStripePattern()) {
result = true;
}
}
return result;
}
all the answers given above answers your question so i would like to add this too.
keep in mind that the equals method called belongs to the object method. so it would be wise for you to override the equals method to fit the needs of your program. and when you override equals make sure you override the hashcode method too..