Class equals method is confusing - java

I'm studying object oriented programming in Java at my school and I had to do an exercise to compare Circles.
I had the Circle Class with these
private int id;
private String bgColor;
private String fgColor;
And inside it I had to use the equals method to compare two circles (by using these three attributes): a circle is equal to other circle if its radius and the bg and fgColor are the same.
public boolean equals(Object obj) {
boolean found;
if (obj == null) {
found = false;
}
if (getClass() != obj.getClass()) {
found = false;
}
final Circle other = (Circle) obj;
if (Double.doubleToLongBits(this.radius) == Double.doubleToLongBits(other.radius)) {
//found = false;
if (Objects.equals(this.bgColor, other.bgColor)) {
//found = false;
if (Objects.equals(this.fgColor, other.fgColor)) {
return true;
}//end if fgColor
else{
found = false;
}
}//end if bgcolor
else{
found = false;
}
}//end if radius
else{
found = false;
}
return found;
}
But my teacher told me that the code above is "confusing", but I don't understand why.
Do you know a better solution?
My teacher wants that we folow this structure (this case is only comparing one property):
public boolean equals (Object obj)
{
boolean b;
if(obj == null)
{
b = false;
}
else
{
if(this == obj)//same object
{
b = true;
}
else
{
if(obj instanceof Book)
{
Book other = (Book) obj;
b = (this.id == other.id);
}
else
{
b = false;
}
}
}
return b;
}

This is about the most concise version (assuming that radius and colors can't be null). The null check for obj is taken care of by the instanceof test:
public boolean equals(Object obj) {
if( ! (obj instanceof Circle ) )
return false;
Circle rhs = (Circle)obj;
return Double.compare( radius, rhs.radius ) == 0 &&
bgColor.equals( rhs.bgColor ) &&
fgColor.equals( rhs.fgColor );
}

public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
// its a Circle so its safe to case
Circle other = (Circle)obj;
// equals ONLY if 3 conditions are met
if (radius == other.getRadius() &&
bgColor.equals(other.getBgColor()) &&
fgColor.equals(other.getFgColor())){
return true;
}
return false;
}

If you are using a IDE (I hope you do) probably it has an option to generate code for equals method.
Eclipse generates something like:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Circle other = (Circle) obj;
if (bgColor == null) {
if (other.bgColor != null)
return false;
} else if (!bgColor.equals(other.bgColor))
return false;
if (fgColor == null) {
if (other.fgColor != null)
return false;
} else if (!fgColor.equals(other.fgColor))
return false;
if (Double.doubleToLongBits(radius) != Double.doubleToLongBits(other.radius))
return false;
return true;
}
And don't forget implements hashcode method when you implements equals method and vicecersa.

Rather than having a single return statement consider using multiple return points to simplify the code. This way you do not need extra boolean variables to hold on to the results of prior conditions.
public class Circle {
public double radius;
public String bgColor;
public String fgColor;
public boolean equals(Object obj) {
if (obj == null) {
return false;
} else if (obj instanceof Circle) {
Circle other = (Circle) obj;
if (Double.compare(this.radius, other.redius) == 0
&& compareStrings(this.fgColor, other.fgColor)
&& compareStrings(this.bgColor, other.bgColor)) {
return true;
} else {
return false;
}
} else {
return false;
}
}
private boolean compareStrings(String a, String b) {
if (a == null && b == null) {
return true;
} else if (a != null) {
return a.equals(b);
} else if (b != null) {
return b.equals(a);
}
return false;
}
}
This solution allows for the possibility that either of the String fgColor or bgColor might be null without throwing a NPE. The String comparison has been extracted into its own function to aid readability and reduce confusion.

As a follow-up to my previous answer:
Writing an equals method that works correctly in the presence of subclassing is extremely non-trivial (see Joshua Bloch's comments in Item 8 of `Effective Java').
Indeed, until relatively recently the was no widely known single method for doing this.
In 2009, the article "How to Write an Equality Method in Java"
by Martin Odersky, Lex Spoon, and Bill Venners shows that this can be achieved in terms of a `canEqual' method.

Related

How do I implement equals for generic types?

Suppose I have a generic container type like this:
public final class Container<T> {
public final T t;
public Container(final T t) {
this.t = t;
}
}
I want to implement equals such that this passes:
final Container<Object> a = new Container<>("Hello");
final Container<String> b = new Container<>("Hello");
assertNotEquals(a, b);
The instances a and b should be different because their type parameter T is different.
However, due to erasure, this is tricky to do. This implementation, for example, is incorrect:
#Override
public boolean equals(final Object obj) {
if (this == obj) {
return true;
}
if (obj != null && obj instanceof Container<?>) {
final Container<?> other = (Container<?>)obj;
return Objects.equals(this.t, other.t);
}
return false;
}
I expect that I will need to store some kind of token for T.
How do I implement equals for generic types?
This does not answer the question.
you can modify a little the Container class and add this field:
public final Class<T> ct;
with that and the equals override then
System.out.println(a.equals(b));
will return false because the equals method will check Class<String> vs Class<Object>
class Container<T> {
public final T t;
public final Class<T> ct;
public Container(final T t, Class<T> ct) {
this.t = t;
this.ct = ct;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = (prime * result) + ((ct == null) ? 0 : ct.hashCode());
result = (prime * result) + ((t == null) ? 0 : t.hashCode());
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Container other = (Container) obj;
if (ct == null) {
if (other.ct != null)
return false;
} else if (!ct.equals(other.ct))
return false;
if (t == null) {
if (other.t != null)
return false;
} else if (!t.equals(other.t))
return false;
return true;
}
}

EQ_SELF_USE_OBJECT Bug

I am writing an equals method in which two names are considered equal if they have the same first, middle, and last names. However, I keep getting the error
"This class defines a covariant version of the equals() method, but
inherits the normal equals(Object) method defined in the base
java.lang.Object class. The class should probably define a boolean
equals(Object) method."
and when I change it to Object other as the parameter, I get a "no such method" error.
public boolean equals(Name other) {
boolean sameFirstName = firstName.equals(other.firstName);
boolean sameMiddleName = middleName.equals(other.middleName);
boolean sameLastName = lastName.equals(other.lastName);
if (sameFirstName && sameMiddleName && sameLastName) {
return true;
}
return false;
}
You have to use Object type for parameter which called 'other'. Then do instance of checking and casting. Please refer to this answer
If you use Java 7 or higher, you can use this code:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(firstName, person.firstName) &&
Objects.equals(middleName, person.middleName) &&
Objects.equals(lastName, person.lastName);
}
And there is an automatically generated equals in IDE:
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return !(firstName != null ? !firstName.equals(person.firstName) : person.firstName != null)
&& !(middleName != null ? !middleName.equals(person.middleName) : person.middleName != null)
&& !(lastName != null ? !lastName.equals(person.lastName) : person.lastName != null);
}
Please notice that there should be NPE check as well.
You are overloading the method equals by having a different parameter to type Object. The following should work for you.
#Override
public boolean equals(Object object) {
if(this == object) return true;
if(!(object instanceof Name)) return false;
Name other = (Name) object;
boolean sameFirstName = firstName.equals(other.firstName);
boolean sameMiddleName = middleName.equals(other.middleName);
boolean sameLastName = lastName.equals(other.lastName);
if (sameFirstName && sameMiddleName && sameLastName) {
return true;
}
return false;
}

how to subtract ArrayList using removeall() in java?

I have array list in java:
List<Correction> Auv=new ArrayList<>();
List<Correction> Produv=new ArrayList<>();
then I want to substract Produv value by Auv, here's an example:
Produv.add(new Correction("a","b"));
Produv.add(new Correction("a","c"));
Produv.add(new Correction("b","d"));
Produv.add(new Correction("b","c"));
Auv.add(new Correction("c","a"));
Auv.add(new Correction("b","c"));
Produv.removeall(Auv);
but nothing subtracted, the array still contain it initial value, is there any way to do this?
I try to override equals(), and still got the same result
here the code of my Correction class:
public class Correction {
private String node0;
private String node1;
public Correction(String node0, String node1) {
this.node0 = node0;
this.node1 = node1;
}
public void setNode0(String node0){
this.node0=node0;
}
public void setNode1(String node1){
this.node1=node1;
}
public String getNode0(){
return node0;
}
public String getNode1(){
return node1;
}
#Override
public boolean equals(Object object){
boolean same = false;
if (object != null && object instanceof Correction)
{
same = this.node0 == ((Correction) object).node1 && this.node1 == ((Correction) object).node1;
}
return same;
}
}
Solved!!
it just simply a mistake on overriding equals() method(thank's guys)
here my correction:
#Override
public boolean equals(Object object){
boolean same = false;
if (object != null && object instanceof Correction)
{
same = (this.node0 == ((Correction) object).node1 && this.node1 == ((Correction) object).node0)||(this.node0 == ((Correction) object).node0 && this.node1 == ((Correction) object).node1);
}
return same;
}
Your equals method looks wrong. It makes more sense to compare this.node0 to ((Correction) object).node0.
I think it should be:
public boolean equals(Object object){
boolean same = false;
if (object != null && object instanceof Correction)
{
same = this.node0.equals(((Correction) object).node0) && this.node1.equals(((Correction) object).node1);
}
return same;
}
Also, is this a typo?
Auv.add("c","a");
Auv.add("b","c");
It should probably be :
Auv.add(new Correction ("c","a"));
Auv.add(new Correction ("b","c"));

What is HashCodeBuilder and EqualsBuilder which is used in overriding the hashcode() and equals() method?

I have to override the equals() method and hascode() method for entity class.
But My question is why to use the HashcodeBuilder and EqualsBuilder to implement it.
Which one is better among this two and why ?
#Override
public int hashCode()
{
return HashCodeBuilder.reflectionHashCode(this, false);
}
#Override
public boolean equals(Object obj)
{
return EqualsBuilder.reflectionEquals(this, obj);
}
OR
#Override
public int hashCode()
{
final int prime = 31;
int result = 1;
result = prime * result + ((userKey == null) ? 0 : userKey.hashCode());
result = prime * result + ((id == null) ? 0 : id.hashCode());
result = prime * result + ((userEntity == null) ? 0 : userEntity.hashCode());
return result;
}
#Override
public boolean equals(Object obj)
{
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
UserKeyEntity other = (UserKeyEntity) obj;
if (UserKey == null)
{
if (other.userKey != null)
return false;
}
else if (!userKey.equals(other.userKey))
return false;
if (id == null)
{
if (other.id != null)
return false;
}
else if (!id.equals(other.id))
return false;
if (userEntity == null)
{
if (other.userEntity != null)
return false;
}
else if (!userEntity.equals(other.userEntity))
return false;
return true;
}
and why?
the Second is by default created by the STS IDE.
Please tell me what exactly the 1st Option is about and why to prefer?
Personally, I wouldn't use reflection to compute equals and hashcode.
As the doc states (for EqualsBuilder.reflectionEquals):
It uses AccessibleObject.setAccessible to gain access to private
fields. This means that it will throw a security exception if run
under a security manager, if the permissions are not set up correctly.
It is also not as efficient as testing explicitly. Non-primitive
fields are compared using equals().
So
You are doing dangerous operations (and you are not even sure that you wouldn't get a SecurityException)
It's less effective because you use reflection to compute those values
As a personal point of view, I really feel like using reflection to compute equals and hashcode from your class is a non-sense. It's like using the wrong tool.
Since you are already using a third party library, I would use the HashCodeBuilder like this :
#Override
public int hashCode() {
return new HashCodeBuilder().append(userKey)
.append(id)
.append(userEntity)
.toHashCode();
}
and same with equals:
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
UserKeyEntity other = (UserKeyEntity) obj;
return new EqualsBuilder().append(userKey, other.userKey)
.append(id, other.id)
.append(userEntity, other.userEntity)
.isEquals();
}
which is a bit more readable than the ones generated by Eclipse, and don't use reflection.
HashcodeBuilder and EqualsBuilder will affect the performance because it uses reflection,it will be slower than than the second one.
You can use the one generated by IDE over HashcodeBuilder and EqualsBuilder.
HashcodeBuilder and EqualsBuilder will be easy to read, understand and its dynamic.

Override equals() method only of a Java object

I am developing an Android application which makes use of the ScanResult object. This object is in the form of:
[SSID: __mynetwork__, BSSID: 00:0e:2e:ae:4e:85, capabilities: [WPA-PSK-TKIP][ESS], level: -69, frequency: 2457, timestamp: 117455824743]
How would I override only the equals() method without creating a customer class which extends it in order to compare only the SSID, BSSID, capabilties, level and frequency attributes only? In other words, in the equals method I want to eliminate the timestamp attribute, so that when I compare these two objects, the equals() method would return a true value:
[SSID: __mynetwork__, BSSID: 00:0e:2e:ae:4e:85, capabilities: [WPA-PSK-TKIP][ESS], level: -69, frequency: 2457, timestamp: 117455824743]
[SSID: __mynetwork__, BSSID: 00:0e:2e:ae:4e:85, capabilities: [WPA-PSK-TKIP][ESS], level: -69, frequency: 2457, timestamp: 117460312231]
Note: When I derive a customer class which extends ScanResult I get the following error when I try to implement a constructor: The constructor ScanResult() is not visible
You just have to implement it without checking the fields you want to ignore. Don't forget to override the hashode() too.
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((field1 == null) ? 0 : field1.hashCode());
result = prime * result + ((field2 == null) ? 0 : field2.hashCode());
...etc
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
ScanResult other = (ScanResult ) obj;
if (field1 == null) {
if (other.field1 != null)
return false;
} else if (!field1.equals(other.field1))
return false;
if (field2 == null) {
if (other.field2 != null)
return false;
} else if (!field2 .equals(other.field2 ))
return false;
}
... etc
}
This is your Overriden equals() Method....
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof ScanResult)) return false;
if(!BSSID.equals(o.BSSID)) return false;
if(!SSID.equals(o.SSID)) return false;
if(!capabilities.equals(o.capabilities)) return false;
if(frequency != o.frequency) return false;
if(level != o.level) return false;
return true;
}
EDIT
Now that the above solution not working, may I suggest:
class ScanResultComparator {
public static boolean equals(ScanResult a, ScanResult b){
if(!a.BSSID.equals(b.BSSID)) return false;
if(!a.SSID.equals(b.SSID)) return false;
if(!a.capabilities.equals(b.capabilities)) return false;
if(a.frequency != b.frequency) return false;
if(a.level != b.level) return false;
return true;
}
}
Extend the ScanResult class and only override the equals() method
class CustomScanResult extends ScanResult {
#Override
public boolean equals(Object o) {
// ... custom logic ...
}
}
simple way use check all variables for true.
example:
public class FtpFile {
public String host;
public String port;
public String fileName;
public String path;
public String username;
public String password;
/**
* Override Equals()
*/
#Override
public boolean equals(Object o) {
try {
if (o == null || getClass() != o.getClass())
return false;
FtpFile p = (FtpFile) o;
return ((host.equals(p.host))
&& (port.equals(p.port))
&& (path.equals(p.path))
&& (username.equals(p.username))
&& (password.equals(p.password)));
} catch (Exception ex) {
return false;
}
}
}

Categories