Canonical equals() method for Java as on Android Developers site - java

Here's how the site suggests you to write an equals() method.
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof MyType)) {
return false;
}
MyType lhs = (MyType) o;
return primitiveField == lhs.primitiveField &&
referenceField.equals(lhs.referenceField) &&
(nullableField == null ? lhs.nullableField == null
: nullableField.equals(lhs.nullableField));
}
Now, I am surely misunderstanding something, but suppose you have two MyType objects m1 and m2, and e.g. if m1.referenceField is null, this is not going to work, because when it reaches
referenceField.equals(lhs.referenceField)
it will throw a NullPointerException. Where could be my logic error?

I believe the point is that this would be a type where referenceField was guaranteed to be non-null, e.g. it's checked in the constructor.
Compare this with nullableField, where the nullity is checked as part of equals.

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 :)

Class compare vs instanceof in equals method java

Like in a title:
My Entity looks like this:
#Entity
public class Example {
#Id
private Integer id;
private String name;
// fields, getters & setters ommited
#Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Example example = (Example) o;
return id != null ? id.equals(examle.id) : examle.id == null;
}
#Override
public int hashCode() {
return id != null ? id.hashCode() : 0;
}
}
Auto generated equals method looks like above.
My questions are:
Why do I need to manually replace:
o == null || getClass() != o.getClass()
into
!(o instanceof
Example)
What will happen if the objects of this class will be placed in java.util.Set? In what part the rule of contract will be violated?
The main difference is that instanceof will return true if o has inheritance of the object whereas getClass comparation will check if both objects are strictly the same class.
As a rule of thumb, in your own classes it is almost always better to use
if (o == null || getClass() != o.getClass()) return false;
This is in particular the case when you plan to create subclasses of your class and override equals, but also when you're not planning that this will work without problem (in most cases). So you don't need to manually replace anything.
The reason is the following. The equals method is required to induce an equivalence relation on objects, in particular it is supposed to be symmetric: if a.equals(b) it must also be the case that b.equals(a) and vice versa. Many classes which use the equals method, such as maps and sets, assume this behavior.
Now, suppose you replace o == null || getClass() != o.getClass() with !(o instanceof Example), and create a subclass a follows:
class Subclass extends Example {
String address;
// fields, getters and setters
public boolean equals(Object o) {
if (!o instanceof Subclass) {
return false;
} else {
return super.equals(o) && Objects.equals(((Subclass)o).address, address);
}
}
}
Now consider the following code:
Example a = new Example();
a.setId(1);
a.setName("A");
Subclass b = new Subclass();
b.setId(1);
b.setName("A");
b.setAddress("Street 1");
System.out.println(a.equals(b)); // Prints true
System.out.println(b.equals(a)); // Prints false
You have now an equals method which is not symmetric, and this may lead to problems when using collections.
Note, however, that in some cases, you actually want to use instanceof. For example, the Javadoc for the equals method of the interface Set specifies that two sets are considered equal when they contain the same elements. So, a HashSet is equal to a TreeSet if they contain the same elements, even though the two sets belong to different classes. In such cases, of course, it is not appropriate to use getClass() == o.getClass()

Java - get propertie names referenced from method

So, I have this class:
public class Book {
private int id;
private String name;
private Something somebody;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Book book = (Book) o;
if (id != book.id && somebody.getId() != book.somebody.getId()) return false;
return true;
}
#Override
public int hashCode() {
return id;
}
}
I would like to get all properties used in this class in equals method - in this case, I would get "id" from Book (since name is not used in equals method), and I would also get "somebody.id" since this is also used in equals method as sub object.
I need this info, so I can serialize only this properties and then during de-serialization on another machine use only that to compare equals. Otherwise it would be too cumbersome to compare full objects for equals (if I have too many sub-properties).
If you are using the Eclipse IDE, I know it has auto-complete options for equals and hashcode that will generate code including comparison of all declared fields. I am not sure if Netbeans or other IDEs have similar functionality, but would be surprised if commonly-used IDEs did not.
Also, your equals method should not compare fields of other objects but invoke equals on them:
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book)) return false; // instanceof is fast these days
Book book = (Book) o;
if (id == book.id &&
// either ensure these are not null or use java.util.Objects.equals()
somebody.equals(book.somebody))
return true;
return false;
}
Furthermore, if your hashcode is merely using id then perhaps your equals can as well. If your object is immutable, then id is all the comparison you would need, and would be quite a bit more efficient. If that is not the case, then it is typical that the checks used in equals are reflected in your hashcode to help prevent hash collisions.

Equals method returning always true JAVA

I am having a problem with overriding equals method in one class, this class has only one attribute which is a 2-dimensional array called grid. This is the constructor:
public World(int n, int m){
this.grid = new Object[n][m];
}
The equals method:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (null == obj)
return false;
if ( !obj instanceof World)
return false;
World other = (World) obj;
if ( !Arrays.deepEquals(grid, other.grid))
return false;
return true;
}
I have already overridden the hashCode() method as well, but the problem is that doesn't matter the case, the equals is always returning true. Does anyone know what is wrong?
Be careful - you're messing with Object here.
Regardless of the actual objects you place into that array, they will all be using Object#equals for its comparison. The reason for that lies in the documentation of Arrays#deepEquals.
Two possibly null elements e1 and e2 are deeply equal if any of the following conditions hold:
e1 and e2 are both arrays of object reference types, and Arrays.deepEquals(e1, e2) would return true
e1 and e2 are arrays of the same primitive type, and the appropriate overloading of Arrays.equals(e1, e2) would return true.
e1 == e2
e1.equals(e2) would return true.
And...guess what Object#equals does:
public boolean equals(Object obj) {
return (this == obj);
}
Your arrays will only ever be equivalent if and only if they contain the exact same instances of stuff between them.
Applying stricter types around your array, such as a concrete class, may help you to get around the issue. We don't know what you're storing in that array, so I can't suggest anything concrete, but look to move away from Object.
Try this-
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof World)) {
return false;
}
World other = (World) obj;
if (!Arrays.deepEquals(this.grid, other.grid))
return false;
return true;
}

equals method overrides equals in superclass and may not be symmetric

I have below Findbugs error for my "equal" method,
This class defines an equals method
that overrides an equals method in a
superclass. Both equals methods
methods use instanceof in the
determination of whether two objects
are equal. This is fraught with peril,
since it is important that the equals
method is symmetrical (in other words,
a.equals(b) == b.equals(a)). If B is a
subtype of A, and A's equals method
checks that the argument is an
instanceof A, and B's equals method
checks that the argument is an
instanceof B, it is quite likely that
the equivalence relation defined by
these methods is not symmetric.
I can not post the code here for security violataion. Please let me know what is the error?
It says that the contract of equals() implies that, a.equals(b) is true if and only if b.equals(a) is true.
If B extends A, in A.equals(Object obj) you probably will have
if !(obj instanceof A) return false;
and in B.equals(Object obj) you will have
if !(obj instanceof B) return false;
Here is the asymmetry: an instance of B makes (b instanceof A) true, while an instance of A makes (a instanceof B) false. So it means a risk than a.equals(b) is true and b.equals(a) is false.
You can use the similar construction to prevent this error:
public boolean equals(final Object obj)
{
if (obj == null || getClass() != obj.getClass())
{
return false;
}
// ...
instead of
public boolean equals(final Object obj)
{
if (!(o instanceof UniversalIDDefinition))
{
return false;
}
// ...
You can use this too :
if (obj == null || !MyClass.class.isAssignableFrom(obj.getClass())) {
return false;
}

Categories