0

I am trying to implement the following example to override the equality and hashCode method if the class has reference type member but no luck. Any help would be highly appreciated. Thanking you all in advance..

     class Point{
    private int x, y;
    Point (int x, int y)
    {
        this.x =x;
        this.y = y;
    }

} 


class Circle 
{
    int radius; 
    Point point ;

    Circle(int x, int y, int radius)
    {
        point = new Point (x ,y);
        this.radius = radius;
    }



    @Override
    public boolean equals(Object arg) {

        if(arg == null) return false;
        if(arg == this) return true;
        if(arg instanceof Circle) 
        {
            if(this.point ==((Circle) arg).point && this.radius == ((Circle)           arg).radius)
            {
                return true;
            }

        } 


        return false;
    }

    @Override
    public int hashCode() {

        return point.hashCode() ^ this.radius;
    }

}


public class TestClass{

    public static void main(String args[])
    {
        Set<Circle> circle = new HashSet<> ();
        circle.add(new Circle(10,20,40));

        System.out.println(circle.contains(new Circle(10,20,40))); //
    }

}

**************************Edited Version, suggested by Alnitak*****************

Now i do get the expected result "true" for equal and "false" for non-equal objects. But the print statement in the Circle's equal method is not executed when the objects values are not equal. I don't know what i am missing, though i get the equality result "false" as expected for non equal objects.

 class Point{
    private int x, y;
    Point (int x, int y)
    {
        this.x =x;
        this.y = y;
    }
    @Override
    public boolean equals(Object arg) {
        if(arg == null ) return false;
        if(arg== this) return true;
        if(arg instanceof Point)
        {
            Point p = (Point) arg;
            if(p.x == x && p.y == y )
            {
                return true;
            }
        }
        return false;

    }
    @Override
    public int hashCode() {

        return (this.x*1124739) ^ (this.y*95);
    }

} 


class Circle 
{
    int radius; 
    Point point ;

    Circle(int x, int y, int radius)
    {

        System.out.println("Circle object created x= " + x);
        point = new Point (x ,y);
        this.radius = radius;
    }



    @Override
    public boolean equals(Object arg) {

        if(arg == null) return false;
        if(arg == this) return true;
        if(arg instanceof Circle)   
        {
            System.out.println("checking circles objects for equality "); 
            // Doesn't get printed when circle objects values are not equal

            Circle c = (Circle) arg;
            return (point.equals(c.point) && radius == c.radius);

        } 


        return false;
    }

    @Override
    public int hashCode() {

        return point.hashCode() ^ this.radius *37;
    }

}


public class TestClass{

    public static void main(String args[])
    {
        Set<Circle> circle = new HashSet<> ();
        circle.add(new Circle(10,20,40));

        System.out.println(circle.contains(new Circle(11,20,40))); //
    }

}
Riaz Ud Din
  • 169
  • 1
  • 1
  • 11
  • 1
    possible duplicate of [How to implement hashCode and equals method](http://stackoverflow.com/questions/2132334/how-to-implement-hashcode-and-equals-method) – default locale Jan 14 '15 at 14:10
  • you shouldn't replace the old code you had in the question - add to it, or put your test version somewhere else, but you've now destroyed the original context of the question. – Alnitak Jan 16 '15 at 09:14
  • ah sorry about that. i will change it back to original question and add the test version. – Riaz Ud Din Jan 16 '15 at 10:44

1 Answers1

5

Your existing Circle.equals() method only checks for referential equality, not value equality. It will always fail because each Circle contains a newly constructed Point object that is unique to that instance.

You should create a proper hashCode and equals method for the Point class.

Within the Circle class you can then use Point.equals() to check for value equality of the held reference, for example:

public boolean equals(Object arg) {
    if (arg == null) return false; 
    if (arg == this) return true;
    if (arg instanceof Circle) {
        Circle c = (Circle)arg;
        return radius == c.radius && point.equals(c.point);
    }
    return false;
}

For the Circle hashcode, a simple option is to generate a local hashcode and xor it with the Point's hashcode.

Alnitak
  • 334,560
  • 70
  • 407
  • 495
  • Thanks very much for detailed explanation. Now i do get the expected result "true" for equal and "false" for non-equal objects. But the print statement in the Circle's equal method is not executed when the objects values are not equal. I don't know what i am missing, though i get the equality result "false" as expected for non equal objects. Could you please check it ? – Riaz Ud Din Jan 16 '15 at 11:23
  • 1
    @RiazUdDin The reason it doesn't call the `equals()` method when the points are different is because the Java collections classes _first_ call the `hashCode` method. It's part of the `Object` contract that objects that are not equal must have different hash codes, so if this first test fails it never reaches the `equals()` test. – Alnitak Jan 16 '15 at 12:12
  • 1
    p.s. note that in my posted code I compare the radius and _then_ the point, since the former test is cheaper and the latter test will be short-circuited by the `&&` operator if the first test fails. – Alnitak Jan 16 '15 at 12:14
  • ahhhhh.. fantastic, super... it explains every thing.. and many many thanks for the explaining the comparison order... its really helpful... – Riaz Ud Din Jan 16 '15 at 12:42