0

So, I have this code written in Java:

import java.util.HashSet;

class Interval{
  long from;
  long to;

  public Interval(long from, long to) {
    this.from = from;
    this.to = to;
  }

  public boolean equals(Interval other) {

    return from == other.from && to == other.to;
  }


 }

public class Test {

   public static void main(String[] args) {

       HashSet<Interval> mySet  = new HashSet<Interval>();

       mySet.add(new Interval(1,2));
       mySet.add(new Interval(1,2));

       for(Interval in : mySet) {
        System.out.println(in.from + " " + in.to);
       }
   }

 }

The problem is that the set doesn't recognize that there is already an interval from 1 to 2. I defined the function equals, but still it doesn't work. I tried implementing the Comparable interface and overloading the compareTo function, but again nothing. Can somebody tell me how can I solve this problem?

Thank you!

Want
  • 820
  • 2
  • 9
  • 20
  • 3
    Override and implement a custom `hashCode()` method in your `Interval` class. – Sotirios Delimanolis Jan 20 '14 at 15:04
  • 1
    You need to override equals and hashcode in your class – Prasad Kharkar Jan 20 '14 at 15:04
  • 2
    Also your `equals` method should be `public boolean equals(Object some)`, otherwise, you're overloading it instead of `@Override`ing it. – Sotirios Delimanolis Jan 20 '14 at 15:05
  • You must provide `equals(Object)` and `hashCode()` implementations which match your definition of equality. – Marko Topolnik Jan 20 '14 at 15:06
  • And it's `equals(Object obj)`, not `equals(Interval other)` ! – Gyro Gearless Jan 20 '14 at 15:06
  • Yes, i did not override the equals method correctly. I provided the hashCode method like this: public int hashCode() { return (int)from - (int)to; } It works, but i don't understand why. For example, don't the two intervals (99,100), (1,2) have the same hashCode? Is it because of the equals method? – Want Jan 20 '14 at 15:13
  • It's OK that two different Intervals have same hashCode. What matters is to make sure that: if two Intervals have equals==true, then hashCode is also the same number for these two Intervals. With your implementation that is guaranteed, that's why it works OK. – peter.petrov Jan 20 '14 at 15:21

2 Answers2

2

You need to override equals from java.lang.Object.

You did not as yours does not accept Object as parameter.

public boolean equals(Object obj) {
    if (obj == null)
        return false;
    else if (this.getClass() != obj.getClass())
        return false;
    else {
        Interval other = (Interval) obj;
        return from == other.from && to == other.to;
    }
}

For hashCode, you can do this for example.

public int hashCode() {
    return new Long(this.from).hashCode();
}

So overall you get this code.

import java.util.HashSet;

class Interval {
    long from;
    long to;

    public Interval(long from, long to) {
        this.from = from;
        this.to = to;
    }

    public boolean equals(Object obj) {
        if (obj == null)
            return false;
        else if (this.getClass() != obj.getClass())
            return false;
        else {
            Interval other = (Interval) obj;
            return from == other.from && to == other.to;
        }
    }

    public int hashCode() {
        return new Long(this.from).hashCode();
    }
}

public class Test003 {

    public static void main(String[] args) {

        HashSet<Interval> mySet = new HashSet<Interval>();

        mySet.add(new Interval(1, 2));
        mySet.add(new Interval2(1, 2));

        for (Interval in : mySet) {
            System.out.println(in.from + " " + in.to);
        }
    }

}
peter.petrov
  • 38,363
  • 16
  • 94
  • 159
1

Use equals and hashCode methods like below it will work perfectly alright

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + (int) (from ^ from >>> 32);
    result = prime * result + (int) (to ^ to >>> 32);
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    Interval other = (Interval) obj;
    if (from != other.from) {
        return false;
    }
    if (to != other.to) {
        return false;
    }
    return true;
}
Jaffar Ramay
  • 1,147
  • 8
  • 13
  • This is not quite right. "getClass() != obj.getClass()" Think what happens if you have Inteval2 which extends Interval but overrides nothing. Interval(1,2) and Interval2(1,2) will be detected as not equal which I guess is not right. – peter.petrov Jan 20 '14 at 15:19
  • @peter.petrov both of these methods are generated by Eclipse and these are perfectly alright :) Interval and IntervalChild should be treated as 2 different objects !!! – Jaffar Ramay Jan 20 '14 at 15:25
  • 1
    OK, that's why I wrote "I guess". Not sure of this Interval and Interval2 case though. If Eclipse does it, then probably it's intended. I didn't generate my two methods with Eclipse. – peter.petrov Jan 20 '14 at 15:27
  • 1
    Updated my equals with what I just learned from you. Hope it's right :) Seems right to me but still not 100% sure. I mean this part: "Interval and Interval2 should be treated as 2 different objects". And +1 from me. – peter.petrov Jan 20 '14 at 15:35