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.
Related
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
So I overwrote an equals function that works with Nodes that contain objects. and it looks like this.
#Override
public boolean equals(Object obj) {
if (this == obj) return true;
if (obj == null) return false;
// Checks if obj is from the same class as this Deque.
if (obj.getClass() != this.getClass()) return false;
#SuppressWarnings("unchecked")
// If obj is from the same class, casts object to DoublyLinkedDeque.
DoublyLinkedDeque<T> object = (DoublyLinkedDeque<T>) obj;
Node other = object.front;
Node self = this.front;
// Checks the info of every Node in this Deque with the other.
while (self != null && other != null) { // Checks
if (!(self.info.equals(other.info))) return false;
self = self.next;
other = other.next;
}
// Otherwise, checks if the front of both Deques is null.
return (self == null && other == null);
}
And it works but I'm not sure how the second invocation of equals work. Specifically how does my code check if the info field (that contains objects) of two nodes are equal without calling super.equals? Nothing in my function has the capability to check if two objects are equal as far as I know, can someone explain this?
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))
So today my data structures final had an exam question that asked this:
"Consider the BinaryTree class and add two recursive methods (independent from each other) named compBT to compare two binary trees. If the two binary trees are structurally identical (i.e., they look the same when the objects stored in the nodes are ignored), each of the two methods returns true; otherwise, each returns false. The first method should be an instance method and the second method should be a class method. Do not access the underlying data structure directly. Note: each method should not take more than 6 lines and be properly indented."
I was able to produce this for the class method:
public static boolean compareTrees(BinaryTree t1, BinaryTree t2) {
if (t1 == null && t2 == null) return true;
if ((t1 == null && t2 != null) || (t1 != null && t2 == null)) return false;
return compareTrees(t1.left, t2.left) && compareTrees(t1.right, t2.right);
}
I felt pretty confident about this answer, but writing the instance method had me totally stumped, especially since it had to be independent from the class method. All I was able to produce was the following:
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
return (compareTrees(this.left) && (t.left)) && (compareTrees(this.right) && compareTrees(t.right));
}
I know the method is incorrect since it will always return false because there is only one base case which will always be met. My thought process behind that particular base case is that if the parameter is null, then return false since there is a structural inequality because the caller cannot be null (only non-null references can call instance methods). But I didn't know what else to do from there.
Can anyone chime in? I thought this problem was pretty interesting.
Edit: adding in BinaryTree class.
Here's what the BinaryTree class looked like:
class BinaryTree {
public int value;
public BinaryTree left;
public BinaryTree right;
public BinaryTree(int x) { value = x;}
}
For instance method, all that changes is that check is before recursion, no in it:
public boolean compareTrees(BinaryTree other) {
if (left == null) != (other.left == null) return false;
if (right == null) != (other.right == null) return false;
if (left != null && !left.compareTrees(other.left)) return false;
if (right != null && !right.compareTrees(other.right)) return false;
return true;
}
I think you've recognized the basic problem. In your static method, you can pass null for both child trees when you call the method recursively. But in your instance method, you can only do that for the parameter. You can't do that for the instance method, since you can't call an instance method on null.
Well, if you can't call the instance method recursively on a null child, you have to handle the null child case before the recursive call. That's the key here, the realization that you will have to rearrange your logic. So your logic will need to be something like this:
If the parameter is null, return false (like you already did)
If the instance's left child is null, then:
2.1 If the parameter's left child is not null, return false
2.2 If the parameter's left child is null, keep going with step 4
If the instance's left child is not null, then call recursively on the left child (it doesn't matter if the parameter's left child is null, because that will be caught be #1), and return false if the recursive call returns false
4-5. Same steps for the right child
If we've gotten this far, and no check has failed, then we can return true
So the code looks something like this:
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
if (this.left == null) {
if (t.left != null) {
return false;
}
}
else if (!this.left.compareTrees(t.left)) {
return false;
}
if (this.right == null) {
if (t.right != null) {
return false;
}
}
else if (!this.right.compareTrees(t.right)) {
return false;
}
return true;
}
EDIT: I just now noticed the requirement that the method not be more than 6 lines. So I guess my answer won't work. On the other hand, I could make it work by compressing a bunch of stuff onto a few lines.
public boolean compareTrees(BinaryTree t) {
if (t == null) return false;
if (this.left == null && t.left != null) return false;
if (this.left != null && !this.left.compareTrees(t.left)) return false;
if (this.right == null && t.right != null) return false;
if (this.right != null && !this.right.compareTrees(t.right)) return false;
return true;
}
I could make it even shorter by combining the last two lines into one. But
if your professor is going to reward compressed, harder-to-read code such as this, and fail cleaner code like I had in my earlier example, shame on him.
More: OK, if your professor measures code quality by a smaller number of lines, this should make him ecstatic, even though all my colleagues would blast it in a code review:
public boolean compareTrees(BinaryTree t) {
return !((t == null) || (this.left == null && t.left != null) || (this.left != null && !this.left.compareTrees(t.left)) || (this.right == null && t.right != null) || (this.right != null && !this.right.compareTrees(t.right)) );
}
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.