instance method equals() - java

I need to create a subclass of HoverFrog called EOHoverFrog. Instances of EOHoverFrog differ from instances of HoverFrog in that two instances of EOHoverFrog are considered equal if their position and height are the same, regardless of their colour.
To do this, I need to write an instance method equals() for EOHoverFrog that overrides the equals() method inherited from Object. The method should accept an argument of any class. If the class of the argument is not the same as the class of the receiver, the method should simply return false, otherwise it should test the equality of the receiver and the argument.
public boolean equals(Object obj)
{
Frog.getClass().getHeight();
HeightOfFrog height = (HeightOfFrog) obj;
return (this.getPosition() == frog.getPosition());
}
please could you tell me whether I'm correct?

public boolean equals(Object obj) {
// my first (incorrect) attempt, read Carlos Heuberger's comment below
// if (!(obj instanceof EOHoverFrog))
// return false;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
// now we know obj is EOHoverFrog and non-null
// here check the equality for the position and height and return
// false if you have any differences, otherwise return true
}

that doesn't seem correct.
public boolean equals(Object obj)
{
Frog.getClass().getHeight(); // you arent assigning this to anything, and class probably
// doesn't have a getHeightMethod()
HeightOfFrog height = (HeightOfFrog) obj; // obj should be an EOHoverFrog; you should
// return false above this if obj is null or the
// wrong class
return (this.getPosition() == frog.getPosition()); // what is frog? It is not defined
// in your example
// you are not comparing heights anywhere.
}
A good way to implement an equals method is:
1) Make sure the other object passed in, obj in your case, is not null and the right class (or classes). In your case, can EOHoverFrog and HoverFrog instances be equal?
2) do your comparisons, something like
// assuming both height and position are on the base calss
var isHeightEqual = this.getHeight() == ((HoverFrog)obj).getHeight();
var isPositionEqual = this.getPosition() == ((HoverFrog)obj).getPosition();
3) now you are in position to check equality
return isHeightEqual && isPositionEqual;

First of all, read this to understand how each equals() method must behave.
Second, if you overrides the equals() method, then it's good practice to add #Override annotation before method.
To learn by examples, you can study a lot of equals() implementations here.

Related

AssertEquals tests in Java doesn't work for Pair objects

Does somebody know why this test fails? These are 2 identical objects with content inside, if I add the toString method after each Pair the test will pass. I tried to override the Equals method from the Object class but still nothing. Any help will be great, thanks
#Override
public int hashCode() {
return Objects.hash(key, value);
}
#Override
public boolean equals(Object obj) {
return super.equals(obj);
}
Pair Class Code
Error assertEquals
They are actual identical
Your problem is that your override of equals doesn't do anything - it just calls the implementation that you overrode. In other words, it has no effect.
You need to override equals in a way that does the comparison that you need. In other words, your equals needs to
check that the Object being compared to is also a Pair,
call equals for the two key fields,
call equals for the two value fields.
If any of these conditions fail, your equals should return false.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Pair<?, ?> pair = (Pair<?, ?>) o;
return key.equals(pair.key) && value.equals(pair.value);
}
This code resolved problem :)

ArrayList.containsAll does not use my custom equals function

The following code is a JUnit test function which fails upon execution.
List<KGramPostingsEntry> a = new ArrayList<KGramPostingsEntry>();
List<KGramPostingsEntry> b = new ArrayList<KGramPostingsEntry>();
KGramPostingsEntry entry = new KGramPostingsEntry(1);
a.add(entry);
entry = new KGramPostingsEntry(1);
b.add(entry);
assertTrue(a.containsAll(b));
It uses the KGramPostingsEntry class:
package ir;
public class KGramPostingsEntry {
int tokenID;
public KGramPostingsEntry(int tokenID) {
this.tokenID = tokenID;
}
public KGramPostingsEntry(KGramPostingsEntry other) {
this.tokenID = other.tokenID;
}
public String toString() {
return tokenID + "";
}
public boolean equals(KGramPostingsEntry other) {
if(other.tokenID == this.tokenID) {
return true;
}
return false;
}
}
As you can see, there is an equals() function in the class that compares the tokenID of the different KGramPostingsEntry objects. It seems to me that this function is not used when calling containsAll() in the test. Further experimentation seems to verify this to be true:
List<KGramPostingsEntry> a = new ArrayList<KGramPostingsEntry>();
List<KGramPostingsEntry> b = new ArrayList<KGramPostingsEntry>();
KGramPostingsEntry entry = new KGramPostingsEntry(1);
a.add(entry);
b.add(entry);
assertTrue(a.containsAll(b));
Here, I'm inserting the same object in both lists. This test does not fail. As far as I've gathered, ArrayList makes a copy object of the object sent to add(), before storing a reference to that object. This means that the objects in the two Lists are not the same (even though they have the same tokenID), and that containsAll() does not check for object reference equality. But if it does not check for object reference equality and does not check the equals() function defined in my code, what does it check? The only plausible option to me is that it checks for object value equality, and that the two objects stored in the first test example are somehow different (even though their only property is tokenID, which is the same in both objects).
What is going on here? How can I make this test succeed the way I want it to?
Here the equals declaration of Object:
public boolean equals(Object obj)
(documentation). You're trying to override this method, but instead you overloaded it:
public boolean equals(KGramPostingsEntry other)
Notice how the argument type in your method is KGramPostingsEntry, which differs from the argument type in Object.equals, namely Object. When a method has the same name but different argument types, it is overloaded, not overridden.
When the ArrayList tries to compare its contents with equals, it'll use the most applicable overridden version of Object.equals. That unfortunately doesn't include your method.
Luckily the fix is easy: you need to implement your equals method with an Object argument:
public boolean equals(Object obj) {
if(obj == null || !(obj instanceof KGramPostingsEntry)) {
return false;
}
KGramPostingsEntry other = (KGramPostingsEntry) obj;
if(other.tokenID == this.tokenID) {
return true;
}
return false;
}
The equals method doesn't have the correct signature. It should be
public boolean equals(Object that) {
// ..
}

How to override the equals method of a subclass

I am trying to sync users between two different locations, therefore I keep existing users in a list, and hence do a comparison at a set time interval to see if the user should be added (new) or just updated.
I have a class User that is the subclass to Principal.
However my compare on the list does not work; I googled a bit and found that you have to override the equals method, and I do - but that code does not seem to be executed, it goes into ArrayList.class (primitive) and executes the contains method there.
Is this because my class already extends the superclass Principal?
What are my options if I want to execute the equals that I defined in User class?
public class User extends Principal
{
// some protected properties
...
#Override
public boolean equals(Object obj) {
return (this.getAlias().equals(((User) obj).getAlias())
&& this.getEmailAddress().equals(((User) obj).getEmailAddress()) && this.getCellNumber().equals(((User) obj).getCellNumber()));
}
}
The Principal class does not override the equals method, and more importantly, the properties I check for equality, is only contained in the subclass - User. Therefore it makes sense to check it here.
So in short, I have an ArrayList of Users, and I would like to check whether a certain User already exists or not. I call compare on the list, but it always fails, indicative that the method equals is not overrided properly in my code.
Any suggestions?
You should not implement equals() (and hashcode()) in a super class.
The reason is that when equals() returns true hashcode() must return same value
Imagine you have class Point2D and class Point3D extending the other.
Shall a point2D be equal to a point3D with same area coordinates?
If so then point3D must return the same hashcode as the "equal" point2D and that means that you cannot not store more that one poin3d with same area coordinates in a Hash bases collection (eg.: as keys in a HashMap).
Overriding equals is not as evident as it looks
equals with null must return false
equals with an object of a different class must return false because of symetry a.equals(b) <=> b.equals(a)
java
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass()!=getClass()) {
return false;
}
return Object.equals(this.getAlias(),((User) obj).getAlias())
&& Object.equals(this.getEmailAddress(),((User) obj).getEmailAddress())
&& Object.equals(this.getCellNumber(),((User) obj).getCellNumber()));
}
Also if object is used in hash collections it must override hashCode so that two objects that are equals must return the same hashCode, the contrary is not true.
The problem probably comes from you instantiating a List<Person>. The compiler can't know if every subclasses of Person override equals. To correct this, you should promise your compiler you'll override this method, which you can do by changing your Person class to an abstract class.
public abstract class Person {
#Override
public abstract boolean equals(Object o);
}
public class User extends Person {
// Some stuff...
#Override
public boolean equals(Object o) {
if (o == null || ! (o instanceof User))
return false;
// etc
}
}
According to the book Effective Java.If you have override the equals method,then you must override the hashcode method.
some advice when you override the equals method:
1. equals with null return false.
2. !(obj instanceof this) return false.
3. cast obj to this class and compare the parameters in the obj and this class.
return the result in the end
You should use the contains methode of the arrayList
https://docs.oracle.com/javase/7/docs/api/java/util/ArrayList.html

Casting down the hierarchy and equals in java

I have the following code
#Override
public boolean equals(Object o) {
if (!(o instanceof ColorPoint))
return false;
return super.equals(o) && ((ColorPoint) o).color == color;
}
And i have the following
Point p = new Point(1, 2);
ColorPoint cp = new ColorPoint(1, 2, Color.RED);
ColorPoint inherits Point. The problem is when I do p.equals(cp) why it return true? I mean in the last return it call super.equal but at that cast what happens? What it returns at that cast with ColorPoint
#Override public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
Point p = (Point)o;
return p.x == x && p.y == y;
}
This is the equal from Point class
You are using the equals method of Point, not the one of ColorPoint.
Change to cp.equals(p) and you'll get false.
Note that you should not implement equals in a way that could make it asymmetrically. Always check, if the classes match, if you want to extend a class:
// in Point class
#Override
public boolean equals(Object other) {
if (other == null || getClass() != other.getClass()) {
return false;
}
Point p = (Point) other;
return p.x == x && p.y == y;
}
In addition to the other answers your implementation of equals() violates the contract as defined in the JavaDocs:
The equals method implements an equivalence relation on non-null object references:
...
It is symmetric: for any non-null reference values x and y, x.equals(y) should return true if and only if y.equals(x) returns true.
...
That means you should not check for o instanceof Point but for o.getClass() == getClass(). With your implementation you get a different result when calling p.equals(cp) and cp.equals(p) and thus you violate that contract. This could cause subtle bugs since most collections rely on that contract.
Your equals method is implemented for ColorPoint. You call equals on Point. It will only check two coordinates - not a color.
You will get false if you call cp.equals(p);
Class hierarchies and equals() don't go well together.
If you implement equals() in superclass using instanceof (so that subclasses can be equal to superclasses), you break the requirement for equals() to by symmetric:
p.equals(cp) // true
cp.equals(p) // false
If you implement it using getClass().equals(other.getClass()), you'll get correct contract, but prevent any subclass instances from ever being equal to your instance - this may be a problem e.g. when using an ORM like Hibernate that creates proxy classes for your classes.
The only situation where equals() seems to work well across multiple classes is when you have an interface and define the contract of equals() in terms of that interface's methods, then write all the implementations so that they honor the contract and only use the info exposed by the interface. This can be seen for example in java.util.List and its common implementations.

this in equals method

I am looking at the equals method, and I see this and I don't understand what it means...I do understand them when I see it in constructors and some methods but its not clear to me when they are in equals method something like this:
(obj == this) ...what does this mean here ? where does it come from ?
I understand when it says something like this.name = name;
from a method like this
#Override
public boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (obj == null || obj.getClass() != this.getClass()) {
return false;
}
sorry it might be a duplicate but I couldnt find anything...
this is the current Object instance. Whenever you have a non-static method, it can only be called on an instance of your object.
You are comparing two objects for equality. The snippet:
if (obj == this) {
return true;
}
is a quick test that can be read
"If the object I'm comparing myself to is me, return true"
. You usually see this happen in equals methods so they can exit early and avoid other costly comparisons.
You have to look how this is called:
someObject.equals(someOtherObj);
This invokes the equals method on the instance of someObject. Now, inside that method:
public boolean equals(Object obj) {
if (obj == this) { //is someObject equal to obj, which in this case is someOtherObj?
return true;//If so, these are the same objects, and return true
}
You can see that this is referring to the instance of the object that equals is called on. Note that equals() is non-static, and so must be called only on objects that have been instantiated.
Note that == is only checking to see if there is referential equality; that is, the reference of this and obj are pointing to the same place in memory. Such references are naturally equal:
Object a = new Object();
Object b = a; //sets the reference to b to point to the same place as a
Object c = a; //same with c
b.equals(c);//true, because everything is pointing to the same place
Further note that equals() is generally used to also determine value equality. Thus, even if the object references are pointing to different places, it will check the internals to determine if those objects are the same:
FancyNumber a = new FancyNumber(2);//Internally, I set a field to 2
FancyNumber b = new FancyNumber(2);//Internally, I set a field to 2
a.equals(b);//true, because we define two FancyNumber objects to be equal if their internal field is set to the same thing.
this refers to the current instance of the class (object) your equals-method belongs to. When you test this against an object, the testing method (which is equals(Object obj) in your case) will check wether or not the object is equal to the current instance (referred to as this).
An example:
Object obj = this;
this.equals(obj); //true
Object obj = this;
new Object().equals(obj); //false

Categories