Issue
Hi i'm just beginner learning about abstract classes & interfaces.
Everything we build our prof is testing by creating clones and comparing objects.
I've learned overriding the equals() method the detailed way…
@Override
public boolean equals(Object obj){
if (this == obj){
return true;
}
else if (obj == null){
return false;
}
...
else {
Obj x = (*Superclass*)obj;
…
}
I was now wondering if I could replace this long way by a short Version where I change the toString method, do a hashCode of the toString method and compare the hashCodes of my Objects (original & clone).
Would this be ok to do or is there any reason i shouldn't do it? Would I be able to inherit the toString, hashCode and equals method and just adjust the clone() in subclasses if we assume that the subclasses use the same variables?
My idea was following
public abstract *Superclass*{
public String name; //would be private in org. code
public int hp; //would be private in org. code
public Superclass(){
}
@Override
public Superclass clone(){
return this; //(not sure if this is ok to use)
}
@Override
public String toString(){
Class temp = getClass();
return temp.getName() + this.name + " " + this.hp;
}
@Override
public int hashCode(){
int hcModify = 10;
int hcCurrent = this.toString().hashCode();
return hcModify * hcCurrent;
}
@Override
public boolean equals(Object obj){
return this.hashCode() == obj.hashCode())
}
}
Solution
So the first thing to note is that your equals
method will throw an error if obj
is null - you can't use any .
operators on null
.
Your clone
method is dangerous if there's mutability in play - mutability means "values can be changed". Because it just returns a reference, changes will be reflected in both the original and "cloned" values (because they're the same.) This is not what most developers would expect. (I suggest looking up deep vs. shallow clones, which is related.)
x = new Thing()
y = thing.clone()
x.changeInSomeWay()
//is y now also changed?
The method of using hash codes for equality is not necessarily good or bad - it depends on the relation of the object to its hash and toString functions, and if there are colisions. Some objects will have hash
or toString
colisions, where different objects will have the same hash or string representations - particularly large or complex objects, where those representations don't include all of the data that you'd want to be reflected in an equality check.
Yours is actually an example of this. You're using an int hashcode, which only has 2^32
(or whatever) possible values, while Strings have, in principle, infinite possible values; by the pigeonhole principal, there must therefor be multiple objects with different names but the same hashcode.
In general, it's not a safe practice, and can lead to weird, difficult to diagnose errors.
I'm not sure why you're multiplying by 10?
Answered By - Edward Peters
Answer Checked By - Clifford M. (JavaFixing Volunteer)