I'd like my EqualTester generic class to call the overridden equals(...) method of its generic parameter, but it seems to call Object.equals instead. Here is my test code:
import junit.framework.TestCase;
public class EqualityInsideGenerics extends TestCase {
public static class EqualTester<V> {
public boolean check(V v1, V v2) {
return v1.equals(v2);
}
}
public static class K {
private int i;
private Object o;
public K(Object o, int i) {
this.o = o;
this.i = i;
}
public boolean equals(K k) {
return ((k.o != null && k.o.equals(o)) || o == null) && (k.i == i);
}
};
public void testEqual() {
K k1 = new K(null, 0);
K k2 = new K(null, 0);
assertTrue(k1.equals(k2)); // This one ok
EqualTester<K> tester = new EqualTester<K>();
assertTrue(tester.check(k1, k2)); // This one KO!
}
}
Could you please explain why this does not work, and how I could change my EqualTester class?
Is it because K does not actually override the Object.equals() method (because the parameter does not have the correct type)?
Thanks.
You need to code as public boolean equals(Object k), and then cast to k.
Right now you are just overloading the equals method.
It's also useful to add #Override annotation to the method.
When overriding the method signature must match exactly.
Because equals(K k) does not actually override the equals(Object o) method.
You must override equals(Object o) exactly in order for it to work.
Thanks Padmarag and Phill!
A solution that works:
#Override
public boolean equals(Object obj) {
if (!(obj instanceof K)) {
return false;
}
K k = (K)obj;
return ((k.o != null && k.o.equals(o)) || o == null) && (k.i == i);
}
Comments welcome: I started programming in Java only a few days ago...
Related
I need to write abstract class, which looks like this.
public abstract class Value {
public abstract String toString();
public abstract Value add(Value v);
public abstract Value sub(Value v);
public abstract boolean eq(Value v);
public abstract boolean lte(Value v);
public abstract boolean gte(Value v);
public abstract boolean neq(Value v);
public abstract boolean equals(Object other);
public abstract int hashCode();
public abstract Value create(String s);
}
Now I need to make few classe, which inherit from that one. I started from Int class and implemented it like this:
public class Int extends Value {
int val;
public String toString() {
String toStr = Integer.toString(val);
return toStr;
}
public Int add(Value v) {
Int result = new Int();
if(v instanceof Int) {
Int temp = (Int) v;
result.val = val + temp.val;
}
return result;
}
public Int sub(Value v) {
Int result = new Int();
if(v instanceof Int) {
Int temp = (Int) v;
result.val = val - temp.val;
}
return result;
}
public boolean eq(Value o) {
if(this == o) return true;
if(this == null) return false;
if(getClass() != o.getClass()) return false;
Int other = (Int) o;
return toString() == other.toString();
}
public boolean lte(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return this.val < temp.val;
}
return false;
}
public boolean gte(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return this.val > temp.val;
}
return false;
}
public boolean neq(Value v) {
if(v instanceof Int) {
Int temp = (Int) v;
return !eq(temp);
}
return true;
}
public boolean equals(Object o) {
if(this == o) return true;
if(this == null) return false;
if(getClass() != o.getClass()) return false;
Int other = (Int) o;
return toString() == other.toString();
}
public int hashCode() {
Integer hash = val;
return hash.hashCode();
}
public Int create(String s) {
val = Integer.parseInt(s);
return this;
}
}
Everything is compiling and working, but I have no clue if my hashcode() function and equals() are good. Furthermore i want to use create() to make objects like this:
getInstance().create("1234");
Is my method also sufficient?
Everything is compiling and working, but I have no clue if my hashcode() function and equals() are good.
Your equals() should compare int val and not result of toString() of compared objects (this.val == other.val).
Your hashCode() looks good, though I would add #Override to it (same with equals()).
Furthermore i want to use create() to make objects like this: getInstance().create("1234");
Looking at its implementation, it looks fine (i.e. would work according to your needs):
public Int create(String s) {
val = Integer.parseInt(s);
return this;
}
though I don't think you really want to use it with getInstance(). Simply Int.create() would be enough:
public static Int create(String s) {
val = Integer.parseInt(s);
return new Int(val);
}
Note that you would need a private constructor.
Also, as someone noted in the comments, consider using generics instead of inheritance.
The hashCode() method is fine (although I'd add an #Override annotation, just to make the code easier to maintain and avoid mistakes), but the equals(Object) definitely isn't.
Following the logic you have in place, == isn't the right way to compare strings. You should use equals instead (see, e.g., How do I compare strings in Java?). In addition, as Joakim Danielson noted in the comments, this can never be null - you should check if o is null instead:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if(getClass() != o.getClass()) {
return false;
}
Int other = (Int) o;
return toString().equals(other.toString()); // Here!
}
But in all fairness, there's no reason to use toString - you could just compare the internal val:
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null) {
return false;
}
if(getClass() != o.getClass()) {
return false;
}
Int other = (Int) o;
return val == other.val; // Here!
}
First when you override Methods please do it with #Override Annotation. Then i would implement your equals method in another way. Just do return this.val == other.val instead of doing this.toString() == other.toString(). Your toString() method implementation is ok. Your hashCode is good as well. But please remove that create method. Use a constructor instead.
Can I implement equals() method using eq() like this ?
public boolean equals(Object o) {
Value compare = (Value) o;
return eq(compare);
}
I'm trying to make a generic tuple class. It stores its elements as an ArrayList. Of course, this class should override hashcode and equals methods.
How could I make hashcode method for this class? You see, in the code, I am having trouble.
Also, for the equals method, why does the compiler force me to use the '?'. Why couldn't I just use the T?
public static class Tuple<T> {
ArrayList<T> tuple = new ArrayList<>();
public Tuple(ArrayList<T> items) {
for (T item : items) {
tuple.add(item);
}
}
#Override
public int hashCode() {
T sum = ???;
for (T item : tuple) {
sum += item.hashCode();
}
return sum;
}
#Override
public boolean equals(Object o) {
if (o instanceof Tuple<?>) {
Tuple<?> tup= (Tuple<?>) o;
if (tup.tuple.size() != this.tuple.size()) {
return false;
}
for (int i = 0; i < this.tuple.size(); i++) {
if (this.tuple.get(i) != tup.tuple.get(i)) {
return false;
}
}
return true;
} else {
return false;
}
}
}
As mentioned in the comments, we should delegate the hashCode and the equals methods to the ArrayList<T> tuple instance variable. For the hashCode it's trivial. For the equals it's just a little more complicated than that because we don't want our custom Tuple to be equals with an ArrayList. So here it is:
public class Tuple<T> {
// I made this private because I'm pedantric ;)
private final ArrayList<T> tuple = new ArrayList<>();
// this does the same as your code, it's just easier to read
public Tuple(ArrayList<T> items) {
tuple.addAll(items);
}
#Override
public int hashCode() {
return tuple.hashCode();
}
// generated by eclipse
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Tuple other = (Tuple) obj;
if (tuple == null) {
if (other.tuple != null)
return false;
} else if (!tuple.equals(other.tuple))
return false;
return true;
}
}
If you want to deal with the case when the tuple can be null, then you can use a slightly more complex hashCode:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((tuple == null) ? 0 : tuple.hashCode());
return tuple.hashCode();
}
In general, I don't like to write these methods myself. Usually, I make my IDE to generate the stuff. All I need to take care of is to re-generate it when I add new fields. Apache HashCodeBuilder and EqualsBuilder are also great alternatives.
Why does ArrayList's contains(Object o) does not run my overridden equals(Object o) method? Consider this code:
private class TargetRC {
public RComponent rc;
public TargetRC(RComponent e) {
rc = e;
}
#Override
public boolean equals(Object o) {
if (o instanceof RComponent)
return o == rc;
else
return o == this;
}
}
private ArrayList<TargetRC> list = new ArrayList<TargetRC>();
public void add(RComponent e) {
list.add(new TargetRC(e));
System.out.println(list.contains(e));
}
As you see it is:
Symetric because o == rc when and only when rc == o
Reflexive because rc == rc
for any RComponent used in comparison.
Adding any element through visible here add method prints always false. No println works inside the equals method. Changing == operators to equals does not make any difference. What is wrong here?
You test
list.contains(e)
with e being a RComponent.
So the list calls RComponent.equals(Object) for every element in your list
which always returns false.
Ok, only thing I had to do was to override ArrayList's indexOf method like this:
private ArrayList<TargetRC> list = new ArrayList<TargetRC>(){
#Override
public int indexOf(Object o){
for(int i=0; i<size(); ++i){
if(get(i).equals(o)) return i;
}
return -1;
}
};
If I run the below code then the output is 2 which means that the set contains 2 elements. However I think that set should contain 1 since both the objects are equal based on hashcode() value as well as .equals() method.
Seems like some obvious mistake in my understanding ?
package HELLO;
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) throws Exception {
Set<Alpha> s = new HashSet<Alpha>();
Alpha a1 = new Alpha();
Alpha a2 = new Alpha();
s.add(a1);
s.add(a2);
System.out.println(s.size());
}
}
class Alpha {
int a = 10;
public int hashcode() {
return a;
}
public boolean equals(Object obj) {
return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
}
public String toString() {
return "Alpha : " + a;
}
}
Your hashcode method does not override the Object class's hashCode method and thus your equals method breaks contract since it doesn't agree with the hashCode results, and you can have objects that are "equal" but have different hashCodes.
Remember: You should always use the #Override annotation when overriding methods as this will help you catch this and similar errors.
#Override // ** don't forget this annotation
public int hashCode() { // *** note capitalization of the "C"
return a;
}
Also, you will want to improve your code formatting, especially when posting code here for our review. We will be able to better understand your code and help you if it conforms to standards (that's why standards exist). So try to keep your indentations consistent with all code lines that are in the same block indented at the same level, and you will want to be sure that base level code, including imports, outer class declarations and its end curly brace, is flush left:
import java.util.HashSet;
import java.util.Set;
public class Test {
public static void main(String[] args) throws Exception {
Set<Alpha> s = new HashSet<Alpha>();
Alpha a1 = new Alpha();
Alpha a2 = new Alpha();
s.add(a1);
s.add(a2);
System.out.println(s.size());
}
}
class Alpha {
int a = 10;
#Override
public int hashCode() {
return a;
}
public String toString() {
return "Alpha : " + a;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Alpha other = (Alpha) obj;
if (a != other.a)
return false;
return true;
}
}
For a beautiful review on this, please read: Overriding equals and hashCode in Java
The #Overrides annotation is to override the method with the same name in the super class".
#Override
public int hashCode() {
return a;
}
#Override
public boolean equals(Object obj) {
return (obj instanceof Alpha && ((Alpha) obj).a == this.a);
}
#Override
public String toString() {
return "Alpha : " + a;
}
your method hashcode should be named hashCode (capital letter "C").
If you plan on overriding methods you should use the #Override annotation.
If you had used that annotation, you'd have noticed the problem earlier as the code wouldn't have compiled.
I was going through Joshua Bloch's online Chapter on "overridding equals() method".
Here's the link.
The following section confuses me,
Reflexivity—The first requirement says merely that an object must be
equal to itself. It is hard to imagine violating this requirement
unintentionally. If you were to violate it and then add an instance of
your class to a collection, the collection’s contains method would
almost certainly say that the collection did not contain the instance
that you just added.
Question - Is it possible for a collection's contain method to return false on an instance added to it?
I tried but the result returned is always true.
To illustrate the point, have this simple class:
class C {
private int i;
public C(int i) { this.i = i; }
}
Now, if you do:
C c1 = new C(1);
C c2 = new C(1);
List<C> l = new ArrayList<C>();
l.add(c1);
l.contains(c2) will return false, since c2.equals(c1) is false, in spite of the fact that both instances have the same constructor arguments.
This is because class C does not override .equals() nor .hashCode().
In general, each time your class is bound to be used in a Collection of any kind, you had better override both of these methods. In this case:
// Note: final class, final member -- that makes this class immutable
final class C {
private final int i;
public C(int i) { this.i = i; }
#Override
public int hashCode() { return i; }
#Override
public boolean equals(Object o)
{
// no object equals null
if (o == null)
return false;
// an object is always equal to itself
if (this == o)
return true;
// immutable class: if the class of the other is not the same,
// objects are not equal
if (getClass() != o.getClass())
return false;
// Both objects are of the same class: check their members
return i == ((C) o).i;
}
}
Question - Is it possible for a collection's contain method to return false on an instance added to it?
Not unless the added object's equals() violates the contract, as the quote from the book explains.
As suggested by #Karthik T, try this with an object whose equals() unconditionally returns false (thereby violating the contract).
Here is a demonstration of a collection's contains method returning false for an object that has just been added to the collection. I took a normal equals and hashCode, generated by Eclipse, and changed the equals method to be non-reflexive. Specifically, it returns false when comparing an object to itself.
import java.util.LinkedList;
import java.util.List;
public class Test {
int someValue;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + someValue;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
// Bad. Non-reflexive. Should return true.
return false;
}
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Test other = (Test) obj;
if (someValue != other.someValue)
return false;
return true;
}
public static void main(String[] args) {
List<Test> myList = new LinkedList<Test>();
Test myObject = new Test();
myList.add(myObject);
System.out.println(myList.contains(myObject));
}
}