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;
}
Related
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 :)
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()
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.
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;
}
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.