I am writing the image processing program, and I have a problem with a list.
I have a list with Points.
class Point1{
private int x;
private int y;
Point1(int x,int y)
{
this.x = x;
this.y = y;
}
int getX(){ return this.x; }
int getY() {return this.y; }
}
ArrayList<Point1> list = new ArrayList();
And now, I create new Point, for example new Point(4,3);
I want to check if there is a point in my list which has the same coordinates. The problem is that
list.contains(Object a)
is checking if if on my list there is a particular object. It will work if I put
Point1 first = new Point(1,1);
list.add(first);
list.contains(first) // and this is true
but:
Point second = new Point(2,2);
list.add(second);
list.contains(new Point(2,2)); <- false
how can I check it?
You need to override equals on your Point class. Your Point class must be responsible for determining whether another Point object is "equal" to the current object. An ArrayList will call equals to determine if the object passed in to contains is "equal" to any item in the list.
If you don't override equals, then Point will inherit equals from Object, which will simply see if it's the same exact object. That's why your first code "works", because you are re-using first. It also explains why your second code doesn't "work", because you used a different object.
Also, if you override equals, it's best to override hashCode also (and vice versa).
List determine whether two objects are equal by using equals method.
If your class won't override public boolean equals(Object o){..} method, it will will inherit it from closest supertype which provides that implementation.
If your class doesn't extend any other class, it will means it implicitly extends Object class. So it will inherit equals implementation from it. Problem is that this implementation looks like:
public boolean equals(Object obj) {
return (this == obj);
}
so it uses reference equality operator ==. This means that equals will only return true if object will be compared with itself (references to other objects will always be different than reference to this object).
In your case your equals method to return true also for other instances of Point1 if their state (value of x and y) is equal.
#Override
public boolean equals(Object other) {
if(this == other)
return true;
if(!other instanceof Point1)
return false;
Point1 otherPoint= (Point1)other;
if(this.x == otherPoint.getX() && this.y == otherPoint.getY())
return true;
return false;
}
And you can get the result you want:
BTW while overriding equals method we should also override hashcode method. See Why do I need to override the equals and hashCode methods in Java?
Related
Say I create one object and add it to my ArrayList. If I then create another object with exactly the same constructor input, will the contains() method evaluate the two objects to be the same? Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.
ArrayList<Thing> basket = new ArrayList<Thing>();
Thing thing = new Thing(100);
basket.add(thing);
Thing another = new Thing(100);
basket.contains(another); // true or false?
class Thing {
public int value;
public Thing (int x) {
value = x;
}
equals (Thing x) {
if (x.value == value) return true;
return false;
}
}
Is this how the class should be implemented to have contains() return true?
ArrayList implements the List Interface.
If you look at the Javadoc for List at the contains method you will see that it uses the equals() method to evaluate if two objects are the same.
I think that right implementations should be
public class Thing
{
public int value;
public Thing (int x)
{
this.value = x;
}
#Override
public boolean equals(Object object)
{
boolean sameSame = false;
if (object != null && object instanceof Thing)
{
sameSame = this.value == ((Thing) object).value;
}
return sameSame;
}
}
The ArrayList uses the equals method implemented in the class (your case Thing class) to do the equals comparison.
Generally you should also override hashCode() each time you override equals(), even if just for the performance boost. HashCode() decides which 'bucket' your object gets sorted into when doing a comparison, so any two objects which equal() evaluates to true should return the same hashCode value(). I cannot remember the default behavior of hashCode() (if it returns 0 then your code should work but slowly, but if it returns the address then your code will fail). I do remember a bunch of times when my code failed because I forgot to override hashCode() though. :)
It uses the equals method on the objects. So unless Thing overrides equals and uses the variables stored in the objects for comparison, it will not return true on the contains() method.
class Thing {
public int value;
public Thing (int x) {
value = x;
}
equals (Thing x) {
if (x.value == value) return true;
return false;
}
}
You must write:
class Thing {
public int value;
public Thing (int x) {
value = x;
}
public boolean equals (Object o) {
Thing x = (Thing) o;
if (x.value == value) return true;
return false;
}
}
Now it works ;)
Just wanted to note that the following implementation is wrong when value is not a primitive type:
public class Thing
{
public Object value;
public Thing (Object x)
{
this.value = x;
}
#Override
public boolean equals(Object object)
{
boolean sameSame = false;
if (object != null && object instanceof Thing)
{
sameSame = this.value == ((Thing) object).value;
}
return sameSame;
}
}
In that case I propose the following:
public class Thing {
public Object value;
public Thing (Object x) {
value = x;
}
#Override
public boolean equals(Object object) {
if (object != null && object instanceof Thing) {
Thing thing = (Thing) object;
if (value == null) {
return (thing.value == null);
}
else {
return value.equals(thing.value);
}
}
return false;
}
}
Other posters have addressed the question about how contains() works.
An equally important aspect of your question is how to properly implement equals(). And the answer to this is really dependent on what constitutes object equality for this particular class. In the example you provided, if you have two different objects that both have x=5, are they equal? It really depends on what you are trying to do.
If you are only interested in object equality, then the default implementation of .equals() (the one provided by Object) uses identity only (i.e. this == other). If that's what you want, then just don't implement equals() on your class (let it inherit from Object). The code you wrote, while kind of correct if you are going for identity, would never appear in a real class b/c it provides no benefit over using the default Object.equals() implementation.
If you are just getting started with this stuff, I strongly recommend the Effective Java book by Joshua Bloch. It's a great read, and covers this sort of thing (plus how to correctly implement equals() when you are trying to do more than identity based comparisons)
Shortcut from JavaDoc:
boolean contains(Object o)
Returns true if this list contains the specified element. More formally,
returns true if and only if this list contains at least one element e such
that (o==null ? e==null : o.equals(e))
record overrides equals
You said:
another object with exactly the same constructor input
… and …
Assume the constructor doesn't do anything funny with the input, and the variables stored in both objects are identical.
As other Answers explain, you must override the Object#equals method for List#contains to work.
In Java 16+, the record feature automatically overrides that method for you.
A record is a brief way to write a class whose main purpose is to communicate data transparently and immutably. By default, you simply declare the member fields. The compiler implicitly creates the constructor, getters, equals & hashCode, and toString.
The logic of equals by default is to compare each and every member field of one object to the counterpart in another object of the same class. Likewise, the default implementations of hashCode and toString methods also consider each and every member field.
record Thing( int amount ) {} ;
That’s it, that is all the code you need for a fully-functioning read-only class with none of the usual boilerplate code.
Example usage.
Thing x = new Thing( 100 ) ;
Thing y = new Thing( 100 ) ;
boolean parity = x.equals( y ) ;
When run.
parity = true
Back to your List#contains question.
Thing x = new Thing( 100 );
List < Thing > things =
List.of(
new Thing( 100 ) ,
new Thing( 200 ) ,
new Thing( 300 )
);
boolean foundX = things.contains( x );
When run.
foundX = true
Bonus feature: A record can be declared locally, within a method. Or like a conventional class you can declare a record as a nested class, or as a separate class.
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.
Consider adding an equality method to the following class of simple points:
public class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
// ...
}
// my definition of equals
public boolean equals(Point other) {
return (this.getX() == other.getX() && this.getY() == other.getY());
}
What's wrong with this method? At first glance, it seems to work OK:
Point p1 = new Point(1, 2);
Point p2 = new Point(1, 2);
Point q = new Point(2, 3);
System.out.println(p1.equals(p2)); // prints true
System.out.println(p1.equals(q)); // prints false
However, trouble starts once you start putting points into a collection:
import java.util.HashSet;
HashSet<Point> coll = new HashSet<Point>();
coll.add(p1);
System.out.println(coll.contains(p2)); // prints false
How can it be that coll does not contain p2, even though p1 was added to it, and p1 and p2 are equal objects?
While it is true that you should implement hashCode() when you implement equals(), that is not causing your problem.
That is not the equals() method you are looking for. The equals method must always have the following signature: "public boolean equals(Object object)". Here is some code.
public boolean equals(Object object)
{
if (object == null)
{
return false;
}
if (this == object)
{
return true;
}
if (object instanceof Point)
{
Point point = (Point)object;
... now do the comparison.
}
else
{
return false;
}
}
The Apache EqualsBuilder class is useful for equals implementations. The link is an older version, but still applicable.
If you liked the Apache EqualsBuilder, you will probably like the Apache HashCodeBuilder class as well.
Edit: updated the equals method example for standard shortcuts.
You must implement hashCode() whenever you override equals(). These two work together, and they must give consistent results at all times. Failing to do so produces just the erroneous behaviour you observed.
This is explained in more detail e.g. in Effective Java 2nd Edition, Item 9: Always override hashCode when you override equals.
Works well by overriding hashcode !
Always remember : override hashCode when you override equals.
#Override public int hashCode() {
return (41 * (41 + getX()) + getY());
}
This is my implementations of hashCode.
As per contract on equals() you need to implement hashCode() as well.
From the JavaDoc on equals():
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes.
In addition to the other answers:
If you are using Eclipse as IDE, you can simply use "Source" --> "Generate hashCode() and equals() to get a basic implementation. Do with that what ever you want.
When overriding equals, you also have to override hashCode (in particular, if you are going to use HashSet or HashMap...). A suitable (though not to clever) implementation would be:
int hashCode() {
return x * 31 + y;
}
Another point (no pun intended): You are not actually overriding the equals(Object) method defined in class Object, but instead are defining a new one. The correct way would be:
boolean equals(Object other) {
if (other == this) return true;
else if (!(other instanceof Point)) return false;
else {
Point p = (Point)other;
return x == p.getX() && y == p.getY();
}
}
Note, that the equals method has a pretty strong contract associated with it, which you are to fulfill.
this question is specifically about the performance and to some extent brevity of the various implementation alternatives.
I refreshed myself with this article on implementing equality right. My question particularly corresponds to canEqual (to ensure equivalence relation).
instead of overloading canEquals method to use instanceOf in every class in the hierarchy( instance of paramenter is a compile time class ). Why not use isAssignableFrom ( which is resolved dynamically ) in only the top level class. Makes for much concise code and you dont have to overload a third method.
While, this alternative works. Are there any performance considerations that I need to be aware of?
enum Color {
RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET;
}
class Point {
int x;
int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
#Override public boolean equals(Object other) {
boolean result = false;
if (other instanceof Point) {
Point that = (Point) other;
//Option 1
//result = (that.canEqual(this) && this.getX() == that.getX() && this.getY() == that.getY());
//Option 2
//result = (that.getClass().isAssignableFrom(this.getClass()) && this.getX() == that.getX() && this.getY() == that.getY());
//Option 3
//result = (getClass() == that.getClass() && this.getX() == that.getX() && this.getY() == that.getY());
}
return result;
}
#Override public int hashCode() {
return (41 * (41 + x) + y);
}
public boolean canEqual(Object other) { return (other instanceof Point); }
}
public class ColoredPoint extends Point{
Color color;
public ColoredPoint(int x, int y, Color color) {
super(x, y);
this.color = color;
}
#Override public boolean equals(Object other) {
boolean result = false;
if (other instanceof ColoredPoint) {
ColoredPoint that = (ColoredPoint) other;
result = (this.color.equals(that.color) && super.equals(that));
}
return result;
}
#Override public int hashCode() {
return (41 * super.hashCode() + color.hashCode());
}
#Override public boolean canEqual(Object other) { return (other instanceof ColoredPoint); }
public static void main(String[] args) {
Object p = new Point(1, 2);
Object cp = new ColoredPoint(1, 2, Color.INDIGO);
Point pAnon = new Point(1, 1) {
#Override public int getY() {
return 2;
}
};
Set<Point> coll = new java.util.HashSet<Point>();
coll.add((Point)p);
System.out.println(coll.contains(p)); // prints true
System.out.println(coll.contains(cp)); // prints false
System.out.println(coll.contains(pAnon)); // prints true
}
}
Update: Actually, your method is not technically valid like I first thought, because it breaks the symmetry contract of equals for subclasses that don't override equals:
Point p = new Point(1, 2);
Point pAnon = new Point(1, 1) {
#Override public int getY() {
return 2;
}
};
System.out.println(p.equals(pAnon)); // prints false
System.out.println(pAnon.equals(p)); // prints true
The reason is that p.getClass().isAssignableFrom(pAnon.getClass()) is true while the inverse, pAnon.getClass().isAssignableFrom(p.getClass()) is false.
If you are not convinced by this, try actually running your code and compare it to the version in the article: you will notice that it prints true, false, false, instead of true, false, true like the example in the article.
unless you want to allow comparing classes of different types, the easiest, safest, most concise and probably most efficient impl is:
(getClass() == that.getClass())
All the answers given so far don't answer the question - but point out the equals() contract. Equality must be an equivalence relation (transitive, symmetric, reflexive) and equal objects must have the same hash code. That extends perfectly fine to subclasses - provided subclasses don't themselves override equals() or hashCode(). So you have two choices - you either inherit equals() from Point (so ColoredPoint instances are equal if they have the same coordinates, even if they have a different color), or you override equals() (and now must make sure a Point and a ColoredPoint are never equal).
If you need to perform a pointwise comparison, then don't use equals() - write a method pointwiseEquals() instead.
Whatever you choose to do, you still have to perform the class check in equals().
getClass() == that.getClass()
is clearly the best performer, but it does break if you expect to be able to equality test subclasses that don't themselves override equals() (and in practice, the only way you can guarantee that is to make the class or the equality methods final and not allow any subclasses to override at all). If it's a choice between instanceOf and isAssignableFrom, there's no practical difference, they both in fact perform the same run-time test (the only difference is, instanceOf can perform a compile-time sanity check, but in this case, it can't know anything when the input is just Object). In both cases, the runtime check is identical - check for the target class in the object's listed interfaces (which doesn't apply here, since we're not checking for an interface), or walk up the class hierarchy until we either find the listed class or get to the root.
See my answer for What is the difference between equality and equivalence?.
You can't equate two objects from different classes because it breaks symmetry.
Edit:
It comes down to whether x in the following:
if (other instanceof Point) {
Point that = (Point) other;
boolean x = that.getClass().isAssignableFrom(this.getClass());
}
has the same power as getClass() == that.getClass().
According to #waxwing's answer it doesn't.
Even if it were correct, I don't see any performance benefit here by calling that.getClass().isAssignableFrom.
Here's my Second Answer to the clarified question
Consider when we call Point.equals(ColoredPoint cp);
Point.equals() first checks for
if (other instanceof Point)...
Which passes. Out of the three options presented, all three of them check that the other object, in this case a ColoredPoint, satisfies some more test. The options are:
will only be true if Point is an instanceof ColoredPoint, which is never
will only be true if ColoredPoint is assignable from Point, which is never
will never be true.
From a performance (and design) perspective, there was no value in checking for other instanceof Point, because the actual behavior OP wants (which he has been unable to express) is that for his particular use case, equality between these Objects means they must be the same class.
Therefore, for both performance and design, just use
this.getClass() == that.getClass()
as was suggested by #jthalborn
When a later coder sees instanceof or isAssignableFrom in your code, he will think that subclasses are allowed to equal the base class, which is completely misleading.
I think you solution will fail because it isn't transitive OOPS, symmetric. See The chapter from Effective Java
Point p = new Point(2,3);
ColoredPoint cp = new ColoredPoint(2,3, Color.WHITE);
I believe (haven't run your code) that
p.equals(cp) is true
but
cp.equals(p) is false
Though I don't fully understand your code - it refers to canEquals() which was commented out. The short answer is that you either have to ignore color for equality, or you have to do what #jthalborn suggested.
OK we here we have the example from Effective Java (i have the 2nd Edition 2008).
The example is in ITEM 8: OBEY THE GENERAL CONTRACT WHEN OVERRIDING EQUALS starting from page 37 (I write this in case you want to check).
class ColoredPoint extends Point{} and there are 2 attepts in demostrating why instanceof is BAD. The first attempt was
// Broken - violates symmetry!
#Override public boolean equals(Object o) {
if (!(o instanceof ColorPoint))
return false;
return super.equals(o) && ((ColorPoint) o).color == color;
}
and the second was
// Broken - violates transitivity!
#Override public boolean equals(Object o) {
if (!(o instanceof Point))
return false;
// If o is a normal Point, do a color-blind comparison
if (!(o instanceof ColorPoint))
return o.equals(this);
// o is a ColorPoint; do a full comparison
return super.equals(o) && ((ColorPoint)o).color == color;
}
First of all the second IF will never be reached. If 'o' is not a Point which is a superclass to ColorPoint how might it happen a non-Point to be a ColorPoint ??????
So the second attempt from the beginning is wrong ! Where the only chance for a TRUE comparison is super.equals(o) && ((ColorPoint)o).color == color;, which is not enough !!
a solution here would be:
if (super.equals(o)) return true;
if (!(o instanceof ColorPoint))
if ((o instanceof Point)) return this.equals(o);
else return false;
return (color ==((ColorPoint)o).color && this.equals(o));
obj.getClass() is used for very specific equals(), But your implementations depends of your scope. How do you define that two objects are equal or not? Implement it and it will work accordingly.
I'm trying to write an equals method for objects that compares their fields and return true if they're equal.
private int x, y, direction;
private Color color;
public boolean equals(Ghost other){
if (this.x == other.x && this.y == other.y &&
this.direction == other.direction && this.color == other.color)
return true;
else
return false;
}
What could be wrong with this?
Since color appears to be a Color, that's a class, and therefore a reference type, which means you need to use equals() to compare the colors.
if (/* ... && */ this.color.equals(other.color)) {
As noted in the comments, using == to compare reference types is really comparing memory addresses in Java. It'll only return true if they both refer to the same object in memory.
akf points out that you need to use the base Object class for your parameter, otherwise you're not overriding Object.equals(), but actually overloading it, i.e. providing a different way of calling the same-named method. If you happen to pass an object of a totally different class by accident, unexpected behavior might occur (although then again if they are of different classes it will return false correctly anyway).
#Override
public boolean equals(Object obj) {
if (!(obj instanceof Ghost))
return false;
// Cast Object to Ghost so the comparison below will work
Ghost other = (Ghost) obj;
return this.x == other.x
&& this.y == other.y
&& this.direction == other.direction
&& this.color.equals(other.color);
}
In principle, this looks fine.
Note however that you are comparing using ==. For primitives, this is no problem, but for objects it will check for the same instance, not the same value. This may or may not be what you want. If you are comparing e.g. java.lang.Strings, you'd want to use equals instead (and check for null).
If you are comparing object variables instead of primitive types, you should be using a this.color.equals(other.color) comparison instead.
In your case, it also depends on how you created the Color objects. if you used the static instances (such as Color.BLUE), then actually, it shouldn't matter. If you created the Color object from rgb values, it definitely matters. Either way, it is best to get used to using .equals() for object variables.
One thing to consider is that you are not overriding the equals method from Object, as you are changing the param type. You might find this method will not be used in all cases as you might expect. Instead of:
public boolean equals(Ghost other){
you should have:
public boolean equals(Object other){
and then internally test whether the other param is an instanceof Ghost and cast as necessry.