override equals method in User class - java

I am working on existing project. I have below user class's equals method. when I compare equality with equals I get false on
if (getClass() != other.getClass()) {
return false;
}
The coomplete equals code:
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
User other = (User) obj;
if (getClass() != other.getClass()) {
return false;
}
if (this.getUserId() == null) {
if (other.getUserId() != null) {
return false;
}
} else if (!this.getUserId().equals(other.getUserId())) {
return false;
}
return true;
}
Do I require to check the class type here? If yes, why are my user classes are different? Why can not I put to check class type like below?
if (!(obj instanceof User)){
return false;
}

if (getClass() != other.getClass()) {
return false;
}
This check should be placed before the casting:
User other = (User) obj;
The difference between instanceof and getClass() is that the latter ensures that the type is not a sub-type. So:
User user = new SubUser();
boolean a = user instanceof User;
boolean b = user.getClass() == User.class;
System.out.println(a);
System.out.println(b);
would print:
true
false

You should use the instanceOf method to avoid a ClassCastException later. This Exception will be thrown if you use the equals method with the wrong object type.

First of all, I think you should inverse the lines
User other = (User) obj;
if (getClass() != other.getClass()) {
return false;
}
to become
if (getClass() != other.getClass()) {
return false;
}
User other = (User) obj;
Secondly, the equals method is an important one in the java collections library and in a lot of others as well so you should really think about any implementation details.
Suppose you have an Employee class (with an id) being subclassed into Manager, so you might consider writing an equals method on Employee just checking the id and you are fine. But, are you ? It depends.
So if you check in employee equals method it will return true if you pass a manager. But if you check on class equality by using getClass, it will return false when you pass a manager.
Suppose these 2 classes are stored in a database into an employee table and into a manager table respectively, the database has the id as a column which is defined as as an autoincrement column. Which means you can have an employee with id 100 who is a totally different person than a manager with id 100.
On the other hand you can have a single employee table storing all employees and managers. Hence here if you have an employee object with id 100 and a manager with id 100 then they must be the same person.

For your question, you should put
getClass() != other.getClass()
before
User other = (User) obj;
Equqality is an interesting question. And many people discussed about it. One detail dicussion on equality can be seen in Programming in Scala 2nd Chapter30.

The Effective Java book by Joshua Bloch provides very good suggestions to implement many, what one might consider, standard situations. It includes an approach to implementing the equals method.
Here is a modified implementation:
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof User)) { // this covers the null check
return false;
}
User other = (User) obj; // this is now safe
if ((this.getUserId() == null) && other.getUserId() != null) {
return false
} else if ((this.getUserId() != null) && !this.getUserId().equals(other.getUserId())) {
return false;
}
return true;
}
It is not so obvious, but the instanceof check returns false for null values simply because there is no way identify their type (i.e. nulls are untyped).

As I found, User class from hibernate layer/DAO is not a direct User class. It's sub class of User or a proxy. So, When I check with obj.getClass() it gives false.
In such cases, better not comparing with getClass().
I checked with instanceof.

here you stated that you don't have any subclasses of User so you can use instanceof check.

Related

Problem with Eclipse default equals() implementation

I'm having some problems with the equals method generated by Eclipse.
Suppose I have an Entity Bean with the attributes entityId and name, but I just selected for the equals generation the entityId attribute. So, the code generated by eclipse is the following:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entity other = (Entity) obj;
if (entityId == null) {
if (other.entityId != null)
return false;
} else if (!entityId.equals(other.entityId))
return false;
return true;
}
The problem is that when comparing two different instances of the class Entity that have null as the entityId, the equals method returns true.
For me, this equals implementation is not correct (at least when using it with JPA), because two entities without an entityId are just object that are going (probably) to be persisted as new objects in a database. If I add these two objects to a Set (one to many relationship, for example), after the two insertions the Set is going to have just one element (Sets don't allow duplicates).
So, the question is why Eclipse generates the equals method like this? Do you think is better to implement the equals method with the following code?
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Entity other = (Entity) obj;
if (entityId == null) {
if (other.entityId != null)
return false;
else
return true;
} else if (!entityId.equals(other.entityId))
return false;
return true;
}
Eclipse simply doesn't know about how you will use your class.
Usually if fields have equal values objects considered equal
class Human {
String name;
String petName;
}
Human("Bob", null) is equal to Human("Bob", null).
You case is somewhat special, so you have to made adjustment by yourself.

Which part of the equals() general contract does my equals() not satisfy

I'm fairly new to java and am just trying to get my head around understanding #Override of the equals() and hashcode() methods.
I know for the equals method to be correct it needs to be:
Reflexive: a.equals(a)
Symmetric: a.equals(b) then b.equals(a)
Transitive: a.equals(b) && b.equals(c) Then a.equals(c)
Not null: ! a.equals(null)
I am struggling to pinpoint which of the above properties I am and am not satisfying when writing my overide of the equals method.
I am aware that eclipse can generate these for me, however as I haven't yet gotten the concept fully, writing it out helps me to learn.
I have written out the what I think is the correct way to do it, but when I check with the eclipse generated version I seem to be 'missing' some aspects.
Example:
public class People {
private Name first; //Invariants --> !Null, !=last
private Name last; // !Null, !=first
private int age; // !Null, ! <=0
...
}
What I wrote:
public boolean equals(Object obj){
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
People other = (People) obj;
if (this.age != other.age){
return false;
}
if (! this.first.equals(other.first)){
return false;
}
if (! this.last.equals(other.last)){
return false;
}
return true;
}
vs eclipse generated
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
People other = (People) obj;
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
if (age != other.age)
return false;
if (last == null) {
if (other.last != null)
return false;
} else if (!last.equals(other.last))
return false;
return true;
}
I am missing:
if (this == obj)
return true;
if (getClass() != obj.getClass())
return false;
And for each variable:
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false;
I'm not sure what getClass() is and is my implmentation incorrect?
First piece of code:
if (this == obj)
return true;
This improves performance in case you compare the object reference against itself. Example: a.equals(a);.
Second piece of code:
if (getClass() != obj.getClass())
return false;
This compares if the class of the reference being compared is the same class of this. The difference between using this approach and instanceof is that it's more restrictive when comparing against a sub class. Example:
public class Foo { }
public class Bar extends Foo { }
//...
Foo foo = new Bar();
System.out.println(foo instanceof Bar); //prints true
System.out.println(foo instanceof Foo); //prints true
Foo foo2 = new Foo();
System.out.println(foo.getClass() == foo2.getClass()); //prints false
Which one should you choose? There's no good or bad approach, it will depend on your desired design.
Third piece of code:
if (first == null) {
if (other.first != null)
return false;
} else if (!first.equals(other.first))
return false; //For each variable.
This is simply a null check for each object reference field in the class. Note that if this.first is null then doing this.first.equals(...) will throw a NullPointerException.
I don't think your implementation is incorrect, but a few notes:
if (this == obj)
return true;
Is a performance optimization, it directly tests for reference equality and short-circuits tests where a is a.
if (getClass() != obj.getClass())
return false;
Is similar to your instanceof call, optimizes away a null check. The other calls seem to be null-checks.
You don't need to write
if (obj == null){
return false;
}
if (!(obj instanceof People)){
return false;
}
because null always gives false in instanceof checks. So these lines can be simplified to just
if (!(obj instanceof People)){
return false;
}
As for your main question of whether your method meets the requirements for an equals() method, strictly speaking the answer is no, or at least it's potentially dodgy. This is because it would be possible to extend the class as follows
public class SpecialPeople extends People {
// code omitted
#Override
public boolean equals(Object object) {
if (object == null || object.getClass() != getClass())
return false;
SpecialPeople other = (SpecialPeople) object;
return other.getAge() == getAge()
&& other.getFirst().equals(getFirst())
&& other.getLast().equals(getLast());
}
Now suppose a is an instance of People and b is an instance of SpecialPeople. Suppose also that a and b have the same name and age. Then
a.equals(b) == true // instanceof check succeeds
b.equals(a) == false // getClass() check fails
Therefore equals() is not symmetric! For this reason, if you are using instanceof rather than getClass() in equals() you should probably either make the equals() method final or the class final.

Using String's equals() implementation inside another equals() implementation?

Let's say a class Member where member has an Id of type String. I want to know if there might be any problem with using a String equals() implementation inside another implementation. Would it be any better if the field Id was of type Long.
#Override public boolean equals(Object object){
if(object == null) return false;
if(! (object instanceof Member)) return false;
Member member= (Member) object;
if(this.Id.equals(member.Id)) //<==My concern is here
return true;
else
return false;
}
The only problem I see is that you may have more class members besides id and your equals implementation will say true even while two instances differ greatly but have the same id. With this in mind, make sure to have a consistent hashCode implementation alongside to avoid inconsistencies.
Another idea is to define custom comparators e.g.
static Comparator<Member> MEMBER_ID_COMPARATOR = new Comparator<Member>() {
#Override
public int compare(Member first, Member second) {
assert(first.getId() != null);
assert(second.getId() != null);
return first.getId().compareTo(second.getId());
}
}
No problem at all. From this point of view, leave Id as a String. If it's only going to contain numbers, yes, you can use Long or BigInteger (my preference). But this is a different animal whatsoever.
Try this instead
#Override public boolean equals(Object object){
if(object == null) return false;
if(! (object instanceof Member)) return false;
Member member= (Member) object;
if (this.Id == null && member.Id == null)
return true;
else if (this.Id != null && member.Id != null)
return this.Id.equals(member.Id);
else
return false;
}

Override equals method

newbie question here:
So in my university homework I have to override the object class equals method for a new class created by me.
The new class is "Product", each product has an "id" attribute which is unique. So this is how I Overrided it:
#Override
public boolean equals(Object obj) {
final Product other = (Product) obj;
if (id != other.id)
return false;
return true;
}
The thing is that doing this is 1,5 points out of 10 and it made me suspicius to be that easy. So i started searching and I found things like:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final Product other = (Product) obj;
if (id != other.id)
return false;
return true;
}
Which don't make sense for me at all, because I think that the last if check all the other ifs restrictions. What do you guys think?Which is the better way to Override this method?
Thanks!
The second piece of code is better:
It optimizes for x.equals(x), which isn't necessary for correctness, but is a helpful optimization
It copes with x.equals(null) instead of throwing NullPointerException
It handles objects of a completely different class without throwing a ClassCastException which yours would (e.g. x.equals("foo"))
It requires the exact same type to provide a symmetric relationship; otherwise obj.equals(x) could invoke a different method, giving a different result.
The second version is a safe one, I would say a pedantic one. Your version, instead, could launch a ClassCastException because you are assuming that the runtime type of the variable obj is of type product. Which is not true, that's why you should use this.getClass() != obj.getClass() (you could solve this problem also with instanceof operator).
If I do
Product p = new Product();
p.equals("abc");
I get an exception while I should get false.
In addition it manages the product.equals(null) problem, which should return false as stated in equals contract method in documentation. If you don't care about this and you do, inside you equals:
...
Product p = (Product)obj; // obj is null
obj.id // this throws a NullPointerException
The common idiom used in overriding equals() is
#Override
public boolean equals(Object obj) {
if (! (obj instanceof Product) ) return false;
final Product other = (Product) obj;
if (id != other.id)
return false;
return true;
}
In the second version that you posted:
the first if() may be good for
optimization only if the following
checks are too much expensive. But
this is not the case, so that is just
redundant code which is evil.
That version won't work if you define a Product subclass which
does not change the semantics of method equals().
(For example a class which
provides some convenience method but
no additional internal state to the
objects.) This is because of the
third if().
Number 2 is right out of Effective Java for the safest way to override equals. 1 has a nullpointer if Object is null and it isn't as optimized as it could be(doesn't check if ojb is a reference to itself)
The solution suggested by 'Joshua Bloch: Effective Java' is (assuming that Product does not have a superclass other than Object):
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (!(obj instanceof Product)) return false;
final Product other = (Product) obj;
if (id != other.id) return false;
return true;
}
Your first solution suffers from two drawbacks:
new Product(1).equals(null) throws a NullpointerException although it is specified to return false in Object.equals().
new Product(1).equals(new Vector()) throws a ClassCastException although it is specified to return false in Object.equals().
Both of these are remedied by the instance check. The if (this == obj) return true; is often useful for efficiency, but probably not necessary here.
The second solution you posted makes it difficult to write a subclass of Product with good semantics. If you have a subclass
public class SubProduct extends Product {
SubProduct(int id) {
super(id);
}
...
}
you will have !new Product(4).equals(new SubProduct(4)). This violates Liskov's susbstitution principle and is often believed to be not so good. If you have a final class
the second solutions is the same as the above.

An efficient equals(Object o) implementation

I read this SO post after I wrote out the title but still decided to go through with the question on bug-proof implementations of equals in Java. This is my normal implementation
#Override
public boolean equals(Object o){
if(o == null) return false;
if(o instanceof CompositePk == false) return false;
if(this == o) return true;
CompositePk that = (CompositePk)o;
return new EqualsBuilder().append(this.id, that.id)
.append(this.bucketId, that.bucketId)
.isEquals();
}
using Apache's EqualsBuilder to do the mundane stuff. Even easier than this is my Netbean's automatically generated equals(o) implementation
#Override
public boolean equals(Object obj){
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final TemplatesWrapper other = (TemplatesWrapper) obj;
if (this.timeAdded != other.timeAdded && (this.timeAdded == null || !this.timeAdded.equals(other.timeAdded))) {
return false;
}
return true;
}
I take these from 2 diff projects but they both try to accomplish the same thing but using diff approaches. Which style would you rather or are there any flaws you spot?
First of all, there's no need to test for null, then test for instanceof, since foo instanceof Bar evaluates to false when foo is null.
It's weird to compare the result of the instanceof operator to false, since instanceof is a boolean operation.
Comparing classes with getClass() is at best controversial. Joshua Bloch, who wrote much of the Java collections framework and a lot of other important stuff besides, says
This technique ("getClass-based equals
methods") does satisfy the equals
contract, but at great cost. The
disadvantage of the getClass approach
is that it violates the "Liskov
Substitution Principle," which states
(roughly speaking) that a method
expecting a superclass instance must
behave properly when presented with a
subclass instance. If a subclass adds
a few new methods, or trivially
modifies behavior (e.g., by emitting a
trace upon each method invocation),
programmers will be surprised when
subclass and superclass instances
don't interact properly. Objects that
"ought to be equal" won't be, causing
programs to fail or behave
erratically. The problem is
exacerbated by the fact that Java's
collections are based on the equals
method.
You should use instanceof instead of comparing via getClass() unless you have some specific technical reason not to.
After establishing that the other object is comparable to this, you then compare primitives with == and objects with equals. It's more complicated if any of your member objects can be null; you must then write verbose clauses to compare possibly null things to each other (or write a bothNullOrEqual(Object a, Object b) method).
The EqualsBuilder approach looks bogus to me, but that's just a "smell", which I won't argue against technically. In general, I don't like extra method calls in a method that may be called frequently.
The Apache one is bogus because it tests for null and uses the getClass() comparison.
Here's mine:
#Override
public boolean equals(final Object o) {
if (!(o instanceof MyClass))
return false;
final MyClass om = (MyClass)o;
// compare om's fields to mine
}
I would do it this way:
public boolean equals(Object ob) {
if (ob == null) return false;
if (ob == this) return true;
if (!(ob instanceof MyClass)) return false; // OR
if (ob.getClass() != getClass()) return false;
// check relevant members
}
The two lines in the middle are different. One allows for subclasses to be equal (the first one), the other doesn't. Use whichever one is appropriate.
To give you an example, Java's AbstractList class will probably use the second form, because the exact implementation of List is irrelevant. what matters is if the members are equal and in the same position.
Conversely, a Person class should use the first form (instanceof) because if there is a Student subclass and you call Person.equals(Student) it may return true without checking the extra fields in Student whereas Student.equals(Person) will probably return false. If equals() isn't commutative, you're asking for trouble.
I tend to use equals() methods generated by my IDE (IntelliJ IDEA) rather than creating an unnecessary dependency to some Apache library for little gain.
Apache's is better than yours or cletus'.
As far as my vague memory suggests, there is a problem with using instanceof in equals; I can't quite put my finger on why yet, perhaps someone will elaborate. I could be wrong.
-- Edit:
As Chris and Steve helpfully explain below, I was thinking of the "symmetric property" of equals implementation. On this basis, I can back up my claim of prefering the Apache implementation :)
Honestly, the less code you have to write, the better off you are (in most cases).
The code that's generated has been debugged and used by many MANY people. You might as well use what's generated (and if you need to enhance the performance, do so).
The advantage of using the generated code: any time your instance fields changes (and this generated code wasn't modified), you can simply regenerate code.
Sometimes, it's easier to think about maintainability. Rule of thumb: the less code you write yourself, the less you have to debug. If the generated code doesn't take a huge performance hit, generate it!
Explanation: When overriding the equals method, the hashCode() method must be overrided too. So, considering a class with 3 properties as show below and considering that all the properties are significant to equality, the equals() implementation must test all these fields. The order of conditionals isn't important, but all the fields must to be tested for equality to consider the equality between objects at all.
public class SampleClass {
private Long id;
private String description;
private Date creation;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((creation == null) ? 0 : creation.hashCode());
result = prime * result + ((description == null) ? 0 : description.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
boolean isEquals = true;
if (this == obj) { isEquals = true; }
else if (obj == null) { isEquals = false; }
else if (getClass() != obj.getClass()) { isEquals = false; }
else {
SampleClass other = (SampleClass) obj;
if (creation == null) {
if (other.creation != null) isEquals = false;
} else if (!creation.equals(other.creation)) {
isEquals = false;
} else if (description == null) {
if (other.description != null) isEquals = false;
} else if (!description.equals(other.description)) {
isEquals = false;
} else if (id == null) {
if (other.id != null) isEquals = false;
} else if (!id.equals(other.id)) {
isEquals = false;
}
}
return isEquals;
}

Categories

Resources