Ankur
Ankur

Reputation: 51100

How is "sameness" defined for Java objects?

I want to add objects of a custom type to a Set. I have several which are the same, i.e. they have the same values for their public variables.

I don't want more than one instance of a "same" object to be added to the set, but each time a new object is created it is always added.

This is because the equals method for class Object implements the most discriminating possible equivalence relation on objects: "For any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true)."

Can I override the equals method for this object to define it differently?

Thanks everyone the problem is solved

Sameness for java objects is defined by overriding the Java Object's equals() method.

@Override
public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((uri == null) ? 0 : uri.hashCode());
    return result;
}

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Resource))
        return false;
    Resource other = (Resource) obj;
    if (uri == null) {
        if (other.uri != null)
            return false;
    } else if (!uri.equals(other.uri))
        return false;
    return true;
}

Upvotes: 4

Views: 4673

Answers (8)

GKelly
GKelly

Reputation: 3919

You should override the equals, and hashCode methods for your custom type.

Be careful though, you can get into all sorts of shit here: for instance if you have sub-types for your custom type, you can run into other equality problems:

class Point {
    final int x;
    final int y;

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

    @Override
    public boolean equals(Object o) {
        if (o == this) return true;   //If objects equal, is OK
        if (o instanceof Point) {
           Point that = (Point)o;
           return (x == that.x)  && y == that.y);
        }
        return false;
    }
}

class ColoredPoint extends Point {
   final Color color;
   ColoredPoint(int x, int y, Color color) {
      super(x, y);
      this.color = color
   }
}

Point p1 = new Point(1, 2);
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.BLUE);
ColoredPoint cp1 = new ColoredPoint(1, 2, Color.RED);

As it stands, p1, cp1, and cp2 are all equal. However, obviously cp1 and cp2 are not equal. You'll need to implement an equals in ColoredPoint too, to compare ColoredPoint Objects (but this breaks equality between p1 and cp1, or cp2).

Also, make sure your equals has the signature above. It's a common mistake to define it as public equals(Point that)..., which is wrong.

See http://www.artima.com/lejava/articles/equality.html for a full explanation of the rules for equals and hashCode

Upvotes: 2

kvista
kvista

Reputation: 5059

As SLaks said, you should override the equals() and hashCode() methods. When you override equals(), you will take the values into account, for example:

public class MyObject
  public int x;
  public int y;

  public boolean equals(Object obj) {
    return (obj instance of MyObject) && (obj.x==x && obj.y==y);
  }

  public int hashCode() { 
   return (x+y)*31;
  }

}

Upvotes: 2

Wayne
Wayne

Reputation: 60414

Regarding:

I get the feeling that my problem is that the two are not equal, since they are different objects which happen to have the same values.

The default implementation of equals performs the strictest -- the docs say most discriminating -- possible form of equality test, which is to test for identity (i.e. that two references refer to the same location in memory).

This is one form of equality, but it's not always the most useful. What you want to test, usually, is that two objects have the same properties. That's a perfectly natural thing to want to do and unworthy of any angst.

Upvotes: 1

voidnnull
voidnnull

Reputation: 11

As already pointed out by SLaks, overriding the equals() and the hashcode() methods definitely makes sense. To ensure that the equals() method behaves as you want it to - in the method check whether the member variables, which you consider to distinguish two objects, are holding the same set of values or not.

Upvotes: 0

Raman
Raman

Reputation: 1517

Add functionality of Set, checks the hashcode() method & if it returns true then it will call equal(). Each object has different memory location & equals() of Object class just compares the memory location bits to check equality. Hence each object gets added.

For this to work, you will have to add both hashCode() as well as equals() method to your class, and these will compare class specific attributes which as per you are creates the meaning of sameness.

Upvotes: 0

kostja
kostja

Reputation: 61538

You definitely should override equals and hashCode since they are the methods used by Java to define object equality. Per default, all Objects are different.

For details of the implementation, consult this chapter of the great "Effective Java" book by Joshua Bloch.

Upvotes: 1

jjoelson
jjoelson

Reputation: 5941

You can absolutely override equals() to compare the significant fields in your class. However, there are some important things to keep in mind. From http://www.javapractices.com/topic/TopicAction.do?Id=17:

-if you override equals, you must override hashCode.

-hashCode must generate equal values for equal objects.

-equals and hashCode must depend on the same set of "significant" fields. You must use the same set of fields in both of these methods. You are not required to use all fields. For example, a calculated field that depends on others should very likely be omitted from equals and hashCode.

This is basically because the Set data structure is implemented as a hash set; it requires hashCode() to place the object in the underlying array and find it later, and it requires equals() to resolve hash collisions (i.e. multiple objects that hash to the same value).

Here's a nice guide on implementing hashCode(): http://www.javamex.com/tutorials/collections/hash_function_guidelines.shtml

[EDIT]

I'd like to second kostja's advice to read Josh Bloch's chapter on this subject. That's a phenomenal book.

Upvotes: 1

SLaks
SLaks

Reputation: 887365

You need to override the equals() and hashCode() methods to tell the HashSet what you consider equal.

If you're using a TreeSet, you should implement Comparable instead.

Upvotes: 6

Related Questions