this in equals method - java

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

Related

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

Comparison of Java objects [duplicate]

This question already has answers here:
Parentheses around data type?
(5 answers)
Closed 7 years ago.
I'm new to Java, and am reading a Java book; at one point it talks about when you may want to override the built in function, equals(). For instance, if an object has a variable ID, and two objects have the same ID, you may want them to be considered to be equal. It gave example code which looks more or less like:
public boolean equals(Object obj) {
if((obj != null) && (obj instanceof myClass)) {
myClass object1 = (myClass)obj;
if(this.ID == object1.ID) {
return true;
}
}
return false;
}
I don't fully understand what's going on in the third line. I'm unsure about why it's necessary and you can't just compare obj.ID and this.ID in the if() statement. My guess is that it's because obj is just declared as a generic object which may not have an ID, so you need to create a new object, object1 which is of the correct class to look at the ID.
Am I correct here? What exactly is going on in that line?
In your code Object obj is a reference to an Object. The code at this point makes no assumptions about which type of Object it is.
When you do
myClass object1 = (myClass) obj;
you are casting the type of the reference to an object which this will either succeed because it is an instance of that type or fail throwing ClassCastException.
This creates a new reference but the underlying object is unchanged by this, nor is it copied.
Note: the obj != null check is redundant as null is not an instanceof of any class, nor does it trigger an exception. i.e.
Object o = null;
boolean b = o instanceof Object; // always false, never throws an exception.
A shorter version of this method could read.
public boolean equals(Object obj) {
if(obj instanceof myClass) {
myClass object1 = (myClass)obj;
return ID == object1.ID;
}
return false;
}
or even
public boolean equals(Object obj) {
return obj instanceof myClass && ID == ((myClass) obj).ID;
}
In Java 8 you could write
public boolean equals(Object obj) {
return Optional.ofNullable(obj)
.filter(o - > o instanceof myClass)
.map(o -> (myClass) o)
.filter(m -> ID == m.ID)
.isPresent();
}
On the 3rd line, no object is being created.
The first thing you need to understand about java is that there are primitives like int, char, double and objects, which are everything else, and objects are always accessed by reference.
So, Object obj is a reference to objects of type Object, and at runtime it will be referring to some object.
Then, further down, when you say myClass object1 you are not creating any object; you are just declaring a variable called object1 which will be referring to objects of type myClass. But there is no object yet.
So, when you say myClass object1 = (myClass)obj; you are assigning the reference obj to the reference object1. And since it would normally be invalid to make an assignment between different types, you are using a type cast (the (myClass) part) to tell the compiler that you know what you are doing, and you are sure that obj will be pointing to an object of type myClass at that point. So, the compiler allows you to make the assignment.
After the assignment, both obj and object1 are pointing to the same object, but the usefulness of object1 now is that you can view this object as an object of type myClass, so you can access its members.
Your guess is almost correct: obj is declared to have type Object and Object can be anything, a String for example, it does not have to have the member named ID, so, you can't just look at it to compare. So, the code you quoted first check if the obj is of the same type (if it isn't, then you know it does not equal), and then (on the line you are asking about) casts it to that type.
I said, your guess was almost correct, because you suggested that a new object of type myClass is created. This is not true. The assignment myClass object1 = (myClass)obj; does not create any new objects, it merely makes a new variable object1 refer to to the same object referred by obj, and tells the compiler that it should now know that that object is actually of type myClass.
Yes. The third line is inside an if statement that says obj instanceof myClass. At that point you know that it is of type myClass. Assuming myClass has an ID like in your code then you know that both objects have ID properties and you can use those for comparison.
Research the term "Object Casting".
the obj instanceof myClass is making sure that obj is the same type as this. Now we know it is safe to cast and Object obj into a myClass object1
The test for null is not needed, because instanceof is false for nulls.
Just use:
if (obj instanceof myClass) {
Otherwise, your code is fine, assuming ID is a primitive (especially, not a String).

what does obj1 == obj2 actually compare

I am studying Overriding hashCode() and equals(Object obj) methods of Object class.
body of equals(Object obj) method in Object class is :
public boolean equals(Object obj) {
return (this == obj);
}
and hashCode() is native :
public native int hashCode();
I have a class Test with overrided equals(Object obj) and hashCoe() :
public class Test {
public static void main(String[] args){
Test t1 = new Test();
Test t2 = new Test();
System.out.println("t1 toString() : " + t1.toString());
System.out.println("t1, Hex value of hashcode : " + Integer.toHexString(t1.hashCode()));
System.out.println("t2 toString() : " + t2.toString());
System.out.println("t2, Hex value of hashcode : " + Integer.toHexString(t2.hashCode()));
System.out.println(t1.equals(t2));
}
#Override
public int hashCode() {
return 999; //hard coded value is just for testing
}
#Override
public boolean equals(Object obj) {
return (this == obj);
}
}
Output of my Code is :
t1 toString() : demo.Test#3e7
t1, Hex value of hashcode : 3e7
t2 toString() : demo.Test#3e7
t2, Hex value of hashcode : 3e7
false //why it is false
why equals(Object obj) returns false in this case if both objects toString() returns the same reference ID (hashcode) [I am not sure if it compares hashcode or not].
What does == operator actually compare in case of objects?
in this answer, answerer said that == that is, it returns true if and only if both variables refer to the same object, if their references are one and the same.
How does it know that the variables refer to the same object???
How does it know that the variables refer to the same object?
Because the values of the variables are the same references. (Your variables are t1 and t2. The values of those variables are references. Those references are used as a way of navigating to objects, basically.)
Suppose you and I both have pieces of paper with a house's street address on (that's my usual analogy for "variables with references"). How do we check whether they refer to the same house? We see whether the address is the same.
There are some potential twists here, as in some cases the form of the reference may not be the same between two expressions, but that's the basic idea.
(Note that just because I've used "address" in the analogy, that doesn't mean a Java reference is always a memory address. It's "a way of navigating to an object", that's all. It may or may not just be an address.)
From the JVM specification section 2.2:
The Java Virtual Machine contains explicit support for objects. An object is either a dynamically allocated class instance or an array. A reference to an object is considered to have Java Virtual Machine type reference. Values of type reference can be thought of as pointers to objects. More than one reference to an object may exist. Objects are always operated on, passed, and tested via values of type reference.
== will check if both references are the same. You have 2 different objects, no matter they are equivalent, they point to different memory blocks.
The only exception to this rule is String, in special conditions(i.e. invoking .intern() method), but that's really a special case, related to String pool.
If you compare with == equals, the instances of the Object needs to be the same (pointer to the same reference, "same id" in the JVM). The hashcode of the object is'nt checked.
This is why it is a good practice to compare with equals(..) in Java.
Here some code:
Test o1 = new Test();
Test o2 = new Test();
//You can check the ids with System#identityHashCode(Object):
System.out.println(System.identityHashCode(o1));
System.out.println(System.identityHashCode(o2));
o1 == o1 // will be true
o1 == o2 // will be false
o1.equals(o2) //depends on how you have implemented equals() and hashCode() in the Test Object.
The contract between hashCode and Equals is:
objects which are .equals() must have the same .hashCode()
The reverse statement does not need to be true.
In your example, it is exacly the case: you return 999 in .hashCode() and you compare the jvm ids in .equals().
== checks to see if the two objects refer to the same place in memory. In other words, it checks to see if the 2 object names are basically references to the same memory location
EX1:
String obj1 = new String("xyz");
String obj2 = new String("xyz");
obj1==obj2; //False
EX2
String obj1 = new String("xyz");
String obj2 = obj1;
obj1==obj2; //True

How do I use the boolean equals(object o) method and call the object the method is applied to?

This is what my method at the moment looks like:
//this method should check if the pokemon are equal//
public boolean equals(Pokemon other){
boolean equality;
if (**XXXXX** == other)
equality = true;
else
equality = false;
return equality;
}
So this is supposed to compare two objects, but my question is how do I call the object that the method is being applied to? For instance, the main code should apply this equals method to Pokemon a, which looks like:
if (a.equals(other))
System.out.println("Pokemon are equal!");
How do I input or call "a" (the object the method is applied to) into my method so that it compares them to be equal? Because when I replace XXXXX in the code to look like:
if (Pokemon == other)
equality = true;
I get the error:
Pokemon.java:130: error: cannot find symbol
if ( Pokemon == other)
^
symbol: variable Pokemon
location: class Pokemon
Since you're calling .equals() on your object a, the method executes with a as its context, meaning the this keyword will refer to a inside of that method, just like any other method called on any other object.
Also, be careful with using ==. That will see if the two references refer to the same exact object in memory. It is highly unlikely that this is only what you want. More likely you will want to check various member variables on the two Pokemon objects to see if those variables are equal, and then if they are return true to indicate the two Pokemon objects are indeed equal. The variables you choose are up to you and your criteria for what makes two Pokemon "equal".
Often, there will actually be a == check at the beginning of a .equals() implementation, because if it's true, then the method can return true immediately since the references are referring to the exact same object in memory. If the == is false, then you can continue checking member variables or whatever other criteria you have for computing equality.
Note also that you're overloading the .equals() method by giving its arguments signature a reference of type Pokemon instead of type Object. If you want to truly override the base Object.equals() method, you'll want to do:
public boolean equals(Object other) {
// Comparisons
}
You'll need to cast other to a Pokemon object (and use instanceof) if you want to use methods and member variables specific to the Pokemon class. You need this override if you want other JDK (or even your own) code that uses .equals() to call your custom .equals() method, instead of the base Object.equals() one.
You should override the equals method provided by Object within your Pokemon class like this:
#Override
public boolean equals(Object o)
{
// check if the "addresses" of o and this object are the same
if (this == o)
return true;
// check if o is of instance Pokemon
else if (o instanceof Pokemon)
{
// need to convert Object to Pokemon - it is save as we already know that
// the o is actually a Pokemon instance
Pokemon p = (Pokemon)o;
// compare fields of o with fields of this instance
if ((this.someField.equals(p.someField)
&& (....))
return true;
}
return false;
}
Here the equals method first checks if both objects refer to the same instance, if not it checks if o is of instance Pokemon and then compares every single field you need to identify if both objects are equal.
Note however, that this example is incomplete as I don't know what fields you have defined for your Pokemon class. When overriding equals() it is good practice to also override public int hashCode() - here you should include every field you compare in equals within your returning hashCode(). Further reading: http://www.xyzws.com/javafaq/why-always-override-hashcode-if-overriding-equals/20 http://www.javaranch.com/journal/2002/10/equalhash.html
That's what the this keyword does.

instance method equals()

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.

Categories