From what i know, Every equals object must have same hash code. However what if in equals method have multiple if that need to be followed ?
Location is an object, Junction is an object, length is an integer, offset is an integer, section is an object.
I already solved the one when atAJunction method, the hashcode i only used junction as the additional hashcode. And when Section is equal, its section's length is equal to the both location's offset. The hashcode that i used for this is only using section as the hashcode.
The main problem is when they have different section, but same offset and endPoint. its equal but the hashcode is different.
Is there anyone can help with my problem ? Thanks Before. :)
This is my Equals method :
#Override
public boolean equals(Object object) {
if(object == null){
return false;
}
if(!(object instanceof Location)){
return false;
}else{
Location otherLocation = (Location) object;
if(atAJunction() && otherLocation.atAJunction()){
return this.endPoint.getJunction().equals(otherLocation.getEndPoint().getJunction());
}else{
// The Problem Here
if(this.endPoint.equals(otherLocation.endPoint)){
return this.offset == otherLocation.getOffset();
}else{
return this.section.equals(otherLocation.getSection()) &&
this.section.getLength() == (this.offset + otherLocation.getOffset());
}
}
}
}
And this is my Hash Code :
#Override
public int hashCode() {
// creates a polynomial hash-code based on the fields of the class.
final int prime = 13; // an odd base prime
int result = 1; // the hash code under construction
if(atAJunction()){
result = prime * result + this.endPoint.getJunction().hashCode();
}else{
result = prime * result + this.section.hashCode();
}
return result;
}
Firstly what I dont understand is why you need this additional check
return this.section.equals(otherLocation.getSection()) &&
**this.section.getLength() == (this.offset + otherLocation.getOffset());**
Ideally if sections are equal, then length and all should be already covered in it. Comparing internal value of one object with some derived value of other class is error prone, and should be avoided in methods like equals().
You may want to take a look at this book, http://www.amazon.com/Effective-Java-Edition-Joshua-Bloch/dp/0321356683. The auther here explains the relation in hash-code and equals in a decent way. This would be definitely helpful to you.
In your case, what I would suggest is, if you are not very clear about right way to generate hashcode() and equals(), try using codegenerators inbuilt in IDE's like Eclipse or netbeans.
Please visit another resourse For Ex. below.
public class Point {
private final int x;
private final int y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
// ...
}
Than you create Equals and HashCode as in Effective Java
// A better definition, but still not perfect
#Override public boolean equals(Object other) {
boolean result = false;
if (other instanceof Point) {
Point that = (Point) other;
result = (this.getX() == that.getX() && this.getY() == that.getY());
}
return result;
}
#Override public int hashCode() {
return (41 * (41 + getX()) + getY());
}
Related
This question already has an answer here:
Should Equality Comparison of Float / Double Instance Variables in an Equals Method be Exact?
(1 answer)
Closed 3 years ago.
An object of class Foo is considered equal if the double members are within a given range of the other object. Such an error can easily be introduced due to floating point arithmetic.
The method isDoubleEquals and doubleArrayEquals will take care of the equals part but the contract states that the hashcode has to be identical for equal objects.
The default hashcode of doubles will not map close values to the same value, therefore what would be a good approach to get the same hash value for matching doubles?
public class Foo {
double[] values;
public Foo(double[] values) {
this.values = values;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
//TODO Arrays.hashCode will not work with the contract
result = prime * result + Arrays.hashCode(values);
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Foo other = (Foo) obj;
if (!doubleArrayEquals(values, other.values,1e-10))
return false;
return true;
}
private boolean doubleArrayEquals(double[] arr, double[] arr2, double epsilon) {
if (arr== arr2)
return true;
if (arr == null || arr2 == null)
return false;
int length = arr.length;
if (arr2.length != length)
return false;
for(int i = 0; i < length; i++) {
if(!isDoubleEquals(arr[i],arr2[i],epsilon)) {
return false;
}
}
return true;
}
private boolean isDoubleEquals(double needle, double target, double epsilon) {
return Math.abs(needle - target) <= epsilon;
}
}
You cannot properly write equals and hashCode methods which deal with approximate equality.
The contract of equals requires transitivity, and approximate equality is not transitive.
That's not to say that approximate equality is not a useful thing: it's just not what Java's equals (and hashCode) methods are for, and therefore you should define your own method - say, isApproximatelyEqualTo - to support it, without overloading the well-known Java methods.
Lets say I have a class
public class Data{
public int k;
public int l;
public Data(int k, int l){
this.k = k;
this.l = l;
}
public boolean equals(Date m){
if(this.k == m.k && this.l = m.l)
return true;
return false;
}
}
And I add a few Data objects to a ArrayList:
ArrayList<Data> holder = new ArrayList<Data>;
Data one = new Data(0,0);
Data two = new Data(0,4);
Data three = new Data(0,5);
Why does indexOf not find this?:
holder.indexOf(new Data(0,4)); //returns -1
Is indexOf any better than going through the whole array list myself? Or am I missing something.
The indexOf() method does go through the entire list. Here's an excerpt from Java 7 source code:
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++)
if (elementData[i]==null)
return i;
} else {
for (int i = 0; i < size; i++)
if (o.equals(elementData[i]))
return i;
}
return -1;
}
It'd be better to let Java go through it than write it yourself. Just make sure that your equals method is sufficient at finding the object you want. You'll also want to override hashCode() as well.
I won't write your equals method out, but I would recommend that you at least:
Check for null
Test if the instances you're comparing are the same
You don't need to do if(boolean_expr) { return true; }; just return the boolean expression.
Make sure you're actually overriding your equals method - the signature of that requires an Object parameter, not Date.
The signature of your equals method is wrong. You are not overriding the equals in Object, but just overloading it.
To override the behavior of equals method in Object, your signature must exactly match with the one in Object. Try this:
public boolean equals(Object o) {
if(!(o instanceof Data)) return false;
Data other = (Data) o;
return (this.k == other.k && this.l == other.l);
}
In addition, as others suggested, it is a good idea to override hashCode method also for your object to work correctly in map based collections.
The answer from Makoto is right. The same i would say to. But you have some mistakes in your code above.
You wrote "public boolean equals(Date m){". I think, you meant Data instead of Date.
You wrote "if(this.k == m.k && this.l = m.l)". The second condition in if query have to be "==".
To your question:
Makoto's answer is one solution.
My solution is to use the help of eclipse to auto generate hashcode and equals methods. Like this:
public class Data {
// your class code here
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + k;
result = prime * result + l;
return result;
}
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (!(obj instanceof Data)) {
return false;
}
Data other = (Data) obj;
if (k != other.k) {
return false;
}
if (l != other.l) {
return false;
}
return true;
}
}
By convention you want to override hashcode also when you override equals
You will most probably find that the indexOf uses the hashcode method to match the object not the equals
If you use eclise to edit you code - eclipse will generate a good equals and hashcode method for you from the "source" menu.
i'm trying to remove duplicate objects from my array.
I have my custom which is made of two double : x and y.
What i want to do is to remove duplicate ( (x && y) == (x1 && y1)) and if x == x1 i want to keep the object which has the higher y.
ArrayList<MyObject> list = [x(0),y(0)], [x(0),y(0)], [x(0.5),y(0.5], [x(0.5),y(0.6)], [x(1),y(1)];
ArrayList<MyObject> results = [x(0),y(0)], [x(0.5),y(0.6)], [x(1),y(1)];
I tried to implement the equals method but i do not how to use it :
public boolean equals(Object obj) {
if (obj == null || !(obj instanceof MyObject)) {
return false;
}
return (this.x == ((MyObject)obj).x);
}
list is always ordered using Collections.sort by x.
Thanks for all.
Given MyObject like this:
class MyObject {
private final double x;
private final double y;
public MyObject(double x, double y) {
this.x = x;
this.y = y;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
MyObject myObject = (MyObject) o;
if (Double.compare(myObject.x, x) != 0) return false;
if (Double.compare(myObject.y, y) != 0) return false;
return true;
}
#Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(x);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(y);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
}
You can implement a unique method that returns a list with unique elements only:
private List<MyObject> unique(List<MyObject> list) {
List<MyObject> uniqueList = new ArrayList<>();
Set<MyObject> uniqueSet = new HashSet<>();
for (MyObject obj : list) {
if (uniqueSet.add(obj)) {
uniqueList.add(obj);
}
}
return uniqueList;
}
And a unit test for it to verify it works:
#Test
public void removeDups() {
List<MyObject> list = Arrays.asList(new MyObject(0, 0), new MyObject(0, 0), new MyObject(0.5, 0.5), new MyObject(0.5, 0.6), new MyObject(1, 1));
List<MyObject> results = Arrays.asList(new MyObject(0, 0), new MyObject(0.5, 0.5), new MyObject(0.5, 0.6), new MyObject(1, 1));
assertEquals(results, unique(list));
}
Note: it's important to implement both equals and hashCode for this to work,
because of the use of a hash map. But you should always do this anyway in your custom classes: provide appropriate equals and hashCode implementations. Btw, I didn't write those equals and hashCode methods. I let my IDE (IntelliJ) generate them automatically from the fields x and y of the class.
Make sure to override equals() method in your custom Object(MyObject).
Then add them into a Set. Now you have unique result set.
Use a Set instead of a List ...
You have to override equals() and hashCode(). The most IDE can generate that for you!
To "convert" a List to a Set you can simply use this:
ArrayList<MyObject> list = ...
Set<MyObject> mySet = new HashSet<MyObject>(list);
Then you have a set with unique elements. You can iterate over the set like this:
for (MyObject o : mySet){
o.getX();
}
The most optimal solution would be if you could use a Set. However, there are two Set implementations in Java: HashSet and TreeSet. HashSet requires that you declare equals and hashCode methods, while TreeSet requires your class to implement Comparable with a compareTo method or supply a Comparator. Neither solution will work in your case because you want to keep the higher y when x is equal. If you sort/calculate equality based on x, y you will have duplicate x, and if you sort/calculate equality based on x only you will get the first x entered, which is not what you want.
Therefore, what we need to do is:
Sort by x ascending, y descending
Convert to Set that preserves original order, but bases equality only on x
Convert back to list (if necessary)
XAscYdesc Comparator Method (Not accounting for nulls):
public int compare(MyObject left, MyObject right) {
int c = left.x - right.x;
if(c != 0) {
return c;
}
return right.y - left.y;
}
XAsc Comparator Method (Not accounting for nulls):
public int compare(MyObject left, MyObject right) {
return left.x - right.x;
}
(Using the Guava library; it's very useful for one-liners like this):
Collections.sort(list, new XAscYdesc());
Lists.newArrayList(ImmutableSortedSet.copyOf(new XAsc(), list));
You need to order your collection on both x and y with x first (think about it as x and y forming an hypothetical number with x on the left side of the decimal point, and y on the right side: when you sort number in growing order, if the integral parts are equal, you sort on the decimal part).
Now, with an equal predicate, it will be difficult to sort values (you can only tell if they are equal, not if one is before another). Instead, you need to implement the comparable interface, with the following method:
public int compare(Object obj) {
if (obj == null || !(obj instanceof MyObject)) {
// raise an Exception
}
MyObject other = (MyObject)obj;
if (x < other.x) return -1;
if (this.x > other.x) return 1;
if (this.y < other.y) return -1;
if (this.y > other.y) return 1;
return 0;
}
If your array is sorted according to this comparison, you just need to keep the last entry with the same x in your array to get what you want. This means that you remove entries unless its successor has a different x.
This method is interesting of you don't want to keep your original data, but only keep the result: it will update the existing array in place, for a complexity of O(n) in time (not counting the sorting, which should happen anyway if I understand your question correctly).
Alternatively, the whole filtering can be achieved by applying a fold on your collection, where folding here is simply keeping the highest y for a same x (as you stated it precisely in your question). Because your collection is already sorted on x, it means that it is naturally partitioned on values of x, so you can build a new collection by accumulating the correct x for each partition in another array. For each element of the array, you compare it with the last inserted entry in your new array, if the x are the same, you replace it with the object with the highest y. If the x are different, you add it to the new array.
The advantage of this approach is that you don't need to change the sorting algorithm, but on the other hand you need a new array. This algorithm should therefore work in O(n) space and time.
Finally, this algorithm may be adapted to an in place update of the original array. It is slightly more complicated, but would let you avoid the extra allocation (crucial on embedded systems).
Pseudo code:
int idx = 0;
while (idx + 1 < Objarray.size()){
MyObj oi = Objarray.get(idx), on = Objarray.get(idx+1);
if (oi.x == on.x) {
if (on.y < oi.y)
Objarray.remove(idx++);
else
Objarray.remove(idx+1);
} else
idx++;
}
Note that while working in constant space, it might be slightly less efficient than the allocating algorithm, because of the way ArrayList works internally (though it should be better than using other usual container types).
/**
*
*/
package test1;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* #author raviteja
*
*/
public class UinquecutomObjects {
/**
* #param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
Employee e1=new Employee();
e1.setName("abc");
e1.setNo(1);
Employee e2=new Employee();
e2.setName("def");
e2.setNo(2);
Employee e3=new Employee();
e3.setName("abc");
e3.setNo(1);
List<Employee> empList=new ArrayList<Employee>();
empList.add(e1);
empList.add(e2);
empList.add(e3);
System.out.println("list size is "+empList.size());
Set<Employee> set=new HashSet<Employee>(empList);
System.out.println("set size is "+set.size());
System.out.println("set elements are "+set);
}
}
class Employee{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getNo() {
return no;
}
public void setNo(int no) {
this.no = no;
}
private int no;
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + no;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (no != other.no)
return false;
return true;
}
}
I'm trying to use HashSet to store objects of a class that I created, but apparently the same objects seem to have two different hashes, which is why the contains method does not realize that the object is already in the HashSet. This leads to my program running out of heap memory.
I don't think I'm doing anything wrong, but I wanted a second opinion anyway. I've done similar operations before which all worked fine, which makes this particularly annoying. I'd appreciate any help.
Here's my code
move1 = new Move(t,s);
if(move1.hashCode()==new Move(t,s).hashCode())
System.out.println("match");
move2 = new Move(s,t);
moves.add(move1);
moves.add(move2);
if(moves.contains(new Move(t,s)))
System.out.println("match found");
Here's the Move class:
public class Move {
private int move1;
private int move2;
Move(int m1, int m2)
{
move1 = m1;
move2 = m2;
}
public String toString()
{
return String.valueOf(move1)+" "+String.valueOf(move2);
}
}
Here's the output I get
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.HashMap.addEntry(HashMap.java:797)
at java.util.HashMap.put(HashMap.java:431)
at java.util.HashSet.add(HashSet.java:194)
at makeMove.<init>(makeMove.java:33)
You need to override the Object#hashCode() method in the Move class to let it return the same hashCode() value for the state of the Move instance. Don't forget to override Object#equals() as well.
See also:
Overriding equals and hashCode in Java
Hint: if you're using an IDE like Eclipse, you can also just autogenerate them. Rightclick somewhere the Move class, choose Source > Generate hashCode() and equals(). Here is how it look like then:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + move1;
result = prime * result + move2;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Move other = (Move) obj;
if (move1 != other.move1)
return false;
if (move2 != other.move2)
return false;
return true;
}
HashSet will determine equality based on calling hashCode() and equals(). You have not implemented these, so you'll inherite them from Object. The hashCode and equals methods of Object is just based on whether the references are equal.
That's why if(move1.hashCode()==new Move(t,s).hashCode()) is false. move1 is a different instance than the instance created by calling new Move(t,s).hashCode()
You'll need to implement hashCode and equals in your Move class.
e.g.(though perhaps non-optimal, and you might want a null safe equals - have your IDE generate them if it can)
public int hashCode() {
return move1 ^ move2 +;
}
public boolean equals(Object o) {
if(!other instanceof Move)
return false;
Move other = (Move)o;
return other.move1 == move1 && other.move2 == move2;
}
You have to override equals() and hashCode().
This may be an option.
import static java.lang.System.out;
public class Move {
private int move1;
private int move2;
Move(int m1, int m2) {
move1 = m1;
move2 = m2;
}
public String toString() {
return String.valueOf(move1)+" "+String.valueOf(move2);
}
public int hashCode() {
return move1 * 31 + move2 * 31;
}
public boolean equals( Object other ) {
if( this == other ) { return true; }
if( other instanceof Move ) {
Move m2 = ( Move ) other;
return this.move1 == m2.move1 && this.move2 == m2.move2;
}
return false;
}
public static void main( String [] args ) {
out.println( new Move(2,3).equals( new Move(2,3)));
out.println( new Move(1,1).hashCode() == new Move(1,1).hashCode() );
}
}
You have to define if the order of the move is relevant ( 1,2 isequals to 2,1 or not )
For more information:
What issues should be considered when overriding equals and hashCode in Java?
I have a class Odp. I want to use TreeSet to keep a sorted collection of Odp objects. However, I've been having problems.
public class OdpStorage {
private TreeSet<Odp> collection = new TreeSet<Odp>();
public addOdp(Odp o) {
return collection.add(o);
}
public int size() {
return collection.size();
}
}
collection.add(Odp o) is supposed to do nothing if it's already in the tree, right? Somehow, this unit test fails:
OdpStorage ts = new OdpStorage();
Odp ftw = new Odp("LOL");
Odp ktr = new Odp("OMG");
ts.addOdp(ftw);
ts.addOdp(ftw); //should do nothing
ts.addOdp(ftw); //should do nothing
ts.addOdp(ftw); //should do nothing
ts.addOdp(ktr);
assertEquals(2, ts.size());
The assertion fails. It expects 2, but the return value is 5. Why? Could the odp.equals() function be messed up?
Similarly, calling collection.contains(o) fails, even when the there is an object in the set X for which o.equals(X) returns true.
The .equals() function of Odp: (generated by Eclipse)
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (!(obj instanceof Odp))
return false;
Gene other = (Odp) obj;
if (sequence == null) {
if (other.sequence != null)
return false;
} else if (!sequence.equals(other.sequence))
return false;
return true;
}
compareTo:
/**
* this = g0
* if they are equal, g1 is presumed to come first
*
* #return -1 if g0 comes before g1; 1 if g0 comes after g1
*/
#Override
public int compareTo(Odp g1) {
if (sequence.length() < g1.getSeq().length()) {
return -1;
}
else if (sequence.length() > g1.getSeq().length()) {
return 1;
}
if (sequence.compareTo(g1.getSeq()) < 0) {
return -1;
}
return 1;
}
hashCode() is not overridden. Problem?
UPDATE
hashCode() is as follows:
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((sequence == null) ? 0 : sequence.hashCode());
return result;
}
But that still doesn't solve the problem.
Your compareTo implementation never returns 0. It should return 0 when the object instances are equal.
It appears that your collection.add(o) is failing to find the object in the backing TreeMap. Does your Odp implement Comparable or are you setting a default Comparable on your TreeSet whose compare method you have implemented? If so, you will need to ensure that your compareTo (for the Comparable), or your Comparator compare method will return 0 if the objects passed in are equals.
EDIT (in response to your comment to the original post):
It is recommended that you override HashCode() whenever you override equals()
EDIT2 in response to your compareTo implementation:
If g0 and g1 are equal, you should return 0. This is the root of the problem.
Mate cleanup your equals, its got too many if/elses. replace it with a nice do/while with lots of condition tests. If all the tests pass then reutrn true...Yes its got "goto" statements but its very easy to read and even easier to insert new conditions as necessary without lots of nesting. Nesting if/elses is evil. Using "elses" is evil and almost always never needed.
#Override
public boolean equals(final Object object) {
boolean equals = false;
do {
if (this == object) {
equals = true;
break;
}
if (false == super.equals(object)) {
break;
}
final DocumentView view = Unsafe.cast(object);
if (false == this.document.equals(view.document)) {
break;
}
if (this.revision != view.revision) {
break;
}
if (false == this.user.equals(view.user)) {
break;
}
if (false == this.timestamp.equals(view.timestamp)) {
break;
}
equals = true;
} while (false);
return equals;
}