The java right implemantion of equals? - java

i try to find out what is the right way to implement java equals.
reading on the net I saw that there are many Thoughts on the subject I narrow down to 2 options
1 using instance of and on using getClass() != obj.getClass()
to follow the rules of :
https://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#equals(java.lang.Object)
this is my final result :
public class Foo {
private List<Long> days;
private String project;
public boolean equals(Object obj) {
if (this == obj)
return true;
//avoid symmetry problem
if (obj == null || getClass() != obj.getClass())
return false;
Foo test = (Foo)obj;
return equals(this.project,test.project) && equals(this.days,test.days);
}
public static boolean equals(Object a,Object b) {
return a == b || a != null && b!=null && a.equals(b);
}
}
what do you say ?

Your code looks good in general. getClass() != obj.getClass() is sufficient enough. It will only fail for positive scenario if someone goes crazy with tricky custom code to load same class with different classloaders.
I would also replace your custom equals on fields with standard Objects.equals at the end:
return Objects.equals(days, foo.days) &&
Objects.equals(project, foo.project);

It's always good to override hashcode when you override equals too.
You may want to custom the equals on the list if the order matter.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Foo foo = (Foo) o;
return Objects.equals(days, foo.days) && Objects.equals(project, foo.project);
}
#Override
public int hashCode() {
return Objects.hash(days, project);
}

You would rewrite your code with the following consideration, we use equals() to compare objects otherwise, = sign used to compare data types

Related

ArrayLIst<PojoClass> list.contain() is not working and return false?

This question ask many times in stackoverflow and i tried all masters answers.
But list.contain() return always false.
and also overide equal() method.
Here is my pojo class
public class RecentStickerPojo
{
File stickerName;
File folderName;
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
RecentStickerPojo other = (RecentStickerPojo) obj;
if (folderName != other.folderName&&stickerName!=other.stickerName)
return false;
return true;
}
}
in activity class
RecentStickerPojo recentStickerPojo=new RecentStickerPojo();
recentStickerPojo.setStickerName(s1);
recentStickerPojo.setFolderName(f1);
list.contains(recentStickerPojo) // return false
Don't forget to implement hashcode.
For strings, use equals (or !equals) and not == (or !=)
Also the equals' last 3 lines can be changed to:
return (folderName.equals(other.folderName) && stickerName.equals( other.stickerName);
No need to override hashcode, as List contains method will use equals method for comparing object. It seems you are comparing File objects directly which can be different. Yes, try by changing last comparison,
if (folderName.equals(other.folderName) && stickerName.equals(other.stickerName))

How to cover equals method in code coverage

New to code coverage, would like to have some insights...
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if ((this.email == null) ? (other.email != null) : !this.email.equals(other.email)) {
return false;
}
if (this.age != other.age && (this.age == null || !this.age.equals(other.age))) {
return false;
}
return true;
}
How do I cover this in jcoco code coverage.
To have this class 100% tested you should create a test for every if and ?: operator. Every part of the code should be tested. For instance, the first if (this == obj), you should have a test where you do
#Test
public void testEqualsSameObj() {
MyClass sut = new MyClass(); // sut == system under test
assertTrue (sut.equals(sut));
}
And now make the next test for passing null:
#Test
public void testEqualsNull() {
MyClass sut = new MyClass(); // sut == system under test
assertFalse (sut.equals(null));
}
And continue with the next condition, until you cover all branches in the code.
You can take the sut from the method and store it in the test class as a member variable.
The equals could have 0% coverage because you might have not included the lombok.config file with with generated annotations as true.
Set,
config.stopBubbling = true;
lombok.addLombokGeneratedAnnotation = true
in lombok.config file
I'm not sure about the what method you are trying to get covered. What I understood from your question is: you are trying to cover equals code of the person.
So in order to cover that
1) have your name property of current object which referred by this as null
2) have your name property of current object as not null to cover the equals part of the code.
To understand more on this learn how ternary (? :) operator works.
I hope this answer helps.

Casting Object to a Pair

I am trying to get my "equals" method to work but am having trouble. This is supposed to be easy but I am new to this. I thought I had to cast otherOject to a pair in order to be able to use .fst and check if the pairs are equal, however I am having difficulty "casting" properly. Any help would be much appreciated. I have the following methods:
public void setFst(T1 aFirst)
{
fst = aFirst;
}
public void setSnd(T2 aSecond)
{
snd = aSecond;
}
public boolean equals(Object otherObject)
{
Pair aPair = (Pair)otherOject; //--------> ???
if(otherObject.fst.equals(this.fst) && otherObject.snd.equals(this.snd))
{
return true;
}
}
Here are the errors I am getting:
./Pair.java:84: cannot find symbol
symbol : variable fst
location: class java.lang.Object
if(otherObject.fst.equals(this.fst) && otherObject.snd.equals(this.snd))
^
./Pair.java:84: cannot find symbol
symbol : variable snd
location: class java.lang.Object
if(otherObject.fst.equals(this.fst) && otherObject.snd.equals(this.snd))
^
This isn't that easy, this has more pitfalls than you'd think.
Your equals method has to allow for having objects belonging to classes other than the class you're writing it for. You have to do is check to see if the argument is also a Pair:
if (otherObject == null) return false;
if (otherObject.getClass() != Pair.class) return false;
After this check is passed you can cast safely, and assign the cast object to a new local variable:
Pair otherPair = (Pair)otherObject;
then use the fields on otherPair for your equals check. At this point you're done with the otherObject parameter and the rest of the equals method shouldn't reference it anymore.
the whole thing would look like
public boolean equals(Object otherObject) {
if (otherObject == null) return false;
if (getClass() != otherObject.getClass()) return false;
Pair otherPair = (Pair)otherObject;
return otherPair.fst.equals(this.fst) && otherPair.snd.equals(this.snd);
}
assuming that fst and snd are not allowed to be null. Calling the equals method on a null member will cause a NullPointerException. To avoid the NPE if fst or snd are null, check if the members are null before calling equals on them:
public boolean equals(Object otherObject) {
// check if references are the same
if (this == otherObject) return true;
// check if arg is null or something other than a Pair
if (otherObject == null) return false;
if (getClass != otherObject.getClass()) return false;
Pair otherPair = (Pair)otherObject;
// check if one object's fst is null and the other is nonnull
if (otherPair.fst == null || this.fst == null) {
if (otherPair.fst != null || this.fst != null) return false;
}
// check if one object's snd is null and the other is nonnull
if (otherPair.snd == null || this.snd == null) {
if (otherPair.snd != null || this.snd != null) return false;
}
// each member is either null for both or nonnull for both
return ((otherPair.fst == null && this.fst == null) || otherPair.fst.equals(this.fst))
&& ((otherPair.snd == null && this.snd == null) || otherPair.snd.equals(this.snd));
}
This last bit is annoying to write, IDEs will generate this stuff for you. Here's what Eclipse generates:
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Pair other = (Pair) obj;
if (fst == null) {
if (other.fst != null)
return false;
} else if (!fst.equals(other.fst))
return false;
if (snd == null) {
if (other.snd != null)
return false;
} else if (!snd.equals(other.snd))
return false;
return true;
}
Remember to implement hashCode too.
The major problem is that after you have cast, you are comparing with the original otherObject, which still is an instance of the Object class, rather than the variable on the Left hand side of your assignment aPair which has the type Pair
So, this should get you going:
public boolean equals(Object otherObject)
{
Pair aPair = (Pair)otherOject; //--------> ???
if(aPair.fst.equals(this.fst) && aPair.snd.equals(this.snd))
{
return true;
}
}
Be careful here though. What you are doing is called unchecked casting. Your compiler might warn you about it. You don't know whether the object being passed to your equals method really can be cast to a Pair - it has to be an instance of Pair or a subclass of Pair for that to be a valid action. So, your cast might fail at runtime if, for instance, you pass a String or Integer object into the method.
EIT
#NathanHughes's more complete answer to this question shows you how to check the casting (using instanceof keyword), so I won't repeat it here.
I recommend the Oracle java tutorial docs for this kind of thing. Check this tutorial for classes and subclasses - the very end is about how to cast and check if it is valid to cast.
Best to do
#Override
public boolean equals(Object otherObject) {
if (otherObject instanceof Pair) {
Pair otherPair = (Pair)otherObject;
return otherPair.fst.equals(fst) && otherPair.snd.equals(snd))
}
return false;
}
Your otherObject is an instance of Object and there is no fst on the Object. Need to change to aPair.fst.equals.

hashset return false when should return true

I'm programming a Maze and I have some problems.
I have:
HashSet<State> closedList = HashSet<State>(); //it hold State objects
My State class look like this:
public class State implements Comparable<State>{
private double f;
private double g;
private String state;
private State prev;
.
.
.
closedList.add(state);
closedList().contains(state); // this equals true
but when I do this:
State temp = State(0,0,"");
temp.setStateName(state.getStateName());
closedList().contains(temp); // this equals false
I have implemented equals and hashCode in State:
#Override
public int hashCode(){
return state.hashCode();
}
#Override
public boolean equals(Object object){
if(this.state == object){
return true;
}
if(object == null || object.getClass() != this.getClass()){
return false;
}
return false;
}
closedList().contains(state); // this equals true
This is a red herring, it only returns true because HashSet checks with == before it makes a call to equals.
What you should try is something like this:
State temp = new State(0, 0, "");
System.out.println(temp.equals(temp));
And you will find this returns false. Why is that? Well let's follow the logic through.
First, you have this check:
if(this.state == object){
return true;
}
If you really intended this to be the way it is, it means you were expecting equals to be called with the String state as the argument, like this:
temp.equals(temp.getStateName())
(And it's the case the above call would return true.) This is incorrect, one would not expect equals to return true for unrelated classes (and in terms of the equals contract, it's the case this is not symmetric). I assume this is unintended and just like a mistake. You should think more carefully about what your code is doing when you are writing it.
Also you should be comparing Strings with equals, not ==.
Then there is this construct:
if(object == null || object.getClass() != this.getClass()){
return false;
}
return false;
This is pointless because first what it implies logically is this, returning false either way:
if(object == null || object.getClass() != this.getClass()){
return false;
} else {
return false;
}
And, second, combined with the earlier check it is not particularly logical:
if(this.state == object)
return true;
if(object.getClass() != this.getClass())
return false;
This is returning true if object is == to a String but returning false if object's class is not State. These are mutually exclusive.
So the equals implementation you wrote doesn't work. The correct equals to match your hashCode is like this:
#Override
public boolean equals(Object object){
if(object == null || object.getClass() != this.getClass()){
return false;
}
State other = (State)object;
return this.state.equals(other.state);
}
First check that the object is not null and that its class is State (you had that part right), then check that the state member is equal to the other object's state member.

How to compare the data of two same Objects in Java

I have a class
MyData
and its object
myData
In that Class MyData .. there are multiple fields
like
int id
String name
String desc
etc ..
Now i have two objects of this class ..
Is it possible to check that if the data of these two object are all the same , Like both objects have the same Id ,same Name ,same Desc ... Without checking each and every field of this object ..(i.e without checking the id,name,desc of Each object myself) As there are dozens of fields of this object .
I am using JAVA with GWT
Some implementation i came across.. Not sure if this is some thing possible .valid
private static String oldSequence = "";
boolean changed(TestSequence sequence) {
String newSequence = serializeToString(sequence);
boolean changed = !newSequence.equals(oldSequence);
oldSequence = newSequence;
return changed;
}
private static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
return b.toByteArray();
}
private static String serializeToString(Object obj) {
try {
return new String(serialize(obj));
} catch (Exception ex) {
return "" + ex;
}
}
Thanks
You should override hashCode() and equals() method. you can generate these from IDE.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof MyData)) return false;
MyData myData = (MyData) o;
if (id != myData.id) return false;
if (!desc.equals(myData.desc)) return false;
if (!name.equals(myData.name)) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + name.hashCode();
result = 31 * result + desc.hashCode();
return result;
}
Now you can compare the objects. That's it.
Conventional way is to override equals and hashCode methods. Java standard libraries, for instance Map s, List s, Set s use the equals and hashCode functions for equality testing. The code below also null-safe;
Here is the code for your case;
public class MyData {
int id;
String name;
String desc;
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyData myData = (MyData) o;
if (id != myData.id) return false;
if (desc != null ? !desc.equals(myData.desc) : myData.desc != null) return false;
if (name != null ? !name.equals(myData.name) : myData.name != null) return false;
return true;
}
#Override
public int hashCode() {
int result = id;
result = 31 * result + (name != null ? name.hashCode() : 0);
result = 31 * result + (desc != null ? desc.hashCode() : 0);
return result;
}
}
and you can test the equality by;
....
Mydata d1 = new...
Mydata d2 = new...
boolean areTheyEqual = d1.equals(d2);
However if you are not allowed to make a compare field by field then you can use byte arrays, there is no need to convert them to strings.
.....
public boolean equals(Object other){
if (this == other) return true;
if (other == null || getClass() != other.getClass()) return false;
byte[] bytesThis = serialize(this);
byte[] bytesOther = serialize(other);
if(bytesOther.length != bytesThis.length) return false;
return Arrays.equals(bytesThis, bytesOther);
}
public static byte[] serialize(Object obj) throws IOException {
ByteArrayOutputStream b = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(b);
o.writeObject(obj);
return b.toByteArray();
}
...
GWT doesn't make a difference to your requirement.
There is no direct way.
You have to define your equality to check weather they are equal or not. That is overriding equals() method.
#Override
public boolean equals(Object obj) { ...
Before doing:Right way to implement equals contract
Like everyone else is saying, you should override the equals() and hashCode() methods.
Note that you don't have to do this manually. In Eclipse you can simply click on Source/generate hashCode() and equals() and it will do the work for you. I am sure other IDEs have similar feature as well.
If you don't want to add any more code when you add a new field, you can try iterating over fields.
You said "Without checking each and every field of this object ..(i.e without checking the id,name,desc of Each object myself) ", I couldn't figure out whether you don't want to check for each field for equality, or don't want to WRITE a check for each field for equality. I assumed the latter since you tried to add an equality comparison method by using bytewise checks.
Anyways, the code to check each field follows. You can copy/paste to any object. If, in the future, you want some fields to be checked and some not, you can use annotations.
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyData myData = (MyData) o;
Field[] fields = this.getClass().getDeclaredFields();
for(Field field:fields){
Object o1 = null;
Object o2 = null;
try {
o1 = field.get(this);
o2 = field.get(o);
} catch (IllegalAccessException e) {
return false;
}
if(o1 == null && o2 != null) return false;
if(o2 == null && o1 != null) return false;
if(o2 == null && o1 == null) continue;
if(!o2.equals(o1)) return false;
}
return true;
}
No.
You have to override the equals() method and compare the objects in that.
Override the equals method of the object in MyData and check the fields independently.
Serialize your objects and compare the results!
You just should be wise in selection of your serialization method.
Override hashCode() and equals() methods
hashCode()
This method provides the has code of an object.
Basically the default implementation of hashCode() provided by Object is derived by mapping the memory address to an integer value. If look into the source of Object class , you will find the following code for the hashCode.
public native int hashCode();
It indicates that hashCode is the native implementation which provides the memory address to a certain extent. However it is possible to override the hashCode method in your implementation class.
equals()
This method is used to make equal comparison between two objects. There are two types of comparisons in Java. One is using “= =” operator and another is “equals()”. I hope that you know the difference between this two. More specifically the .equals() refers to equivalence relations. So in broad sense you say that two objects are equivalent they satisfy the equals() condition.

Categories