Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Overriding "equals" method: how to figure out the type of the parameter?

I'm trying to override equals method for a parameterized class.

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!(obj instanceof Tuple))
        return false;

    Tuple<E> other = (Tuple<E>) obj; //unchecked cast
    if (!a0.equals(other.a0) && !a0.equals(other.a1)) {
        return false;
    }
    if (!a1.equals(other.a1) && !a1.equals(other.a0)) {
        return false;
    }

    return true;
}

How can I make sure that <E> of the other object is the same as this?

like image 311
Nick Heiner Avatar asked Oct 27 '09 04:10

Nick Heiner


People also ask

What is the type of parameter for equals method?

Parameter: This method accepts a mandatory parameter obj which is the object to be compared. Return Value: The method return true if Method object is same as passed object as parameter, otherwise false.

Can you override equals method?

You can override the equals method on a record, if you want a behavior other than the default. But if you do override equals , be sure to override hashCode for consistent logic, as you would for a conventional Java class.

What is the reason for overriding equals () method?

We can override the equals method in our class to check whether two objects have same data or not.

When you are writing equals () method which other method or methods you need to override?

"If two objects are equal using Object class equals method, then the hashcode method should give the same value for these two objects." So, if in our class we override equals() we should override hashcode() method also to follow this rule.


3 Answers

You can do it by retaining a reference to Class<E> type. However, in my opinion, equality tests should be about the values the objects represent rather than the concrete types the values get expressed.

A classic example of this is the Collections API for example. new ArrayList<String>().equals(new LinkedList<Object>()) returns true. While these have completely different types, they represent the same value, namely "an empty collection".

Personally, should two Tuples that represent the same data (e.g. ("a", "b")) be not equal, because one is of type Tuple<String> while the other is Tuple<Object>?

like image 87
notnoop Avatar answered Sep 22 '22 01:09

notnoop


Because of erasure you can't. About the best you could do is store in the tuple class the type you plan for the Tuple to hold in a "java.lang.Class" field member. Then you could compare those fields to make sure the tuple class is holding the same types.

Also see this thread: What is the equivalent of the C++ Pair<L,R> in Java?

It would help if you post more about your class. I'm thinking the unchecked cast and your number of fields you equate means it should be Tuple<E,F> no?

EDIT: here is a useful Pair class I use regularly (you can adapt your Tuple class if needed). Note, similiar to suggestions by others this class just lets the contained members decide the question of equality. Your use case is what should determine whether equality is really based on the type of the contained members.

/**
 * Adapted from http://forums.sun.com/thread.jspa?threadID=5132045
 * 
 * 
 * @author Tim Harsch
 *
 * @param <L>
 * @param <R>
 */
public class Pair<L, R> {

    private final L left;
    private final R right;

    public R getRight() {
        return right;
    } // end getter

    public L getLeft() {
        return left;
    } // end getter

    public Pair(final L left, final R right) {
        this.left = left;
        this.right = right;
    } // end constructor

    public static <A, B> Pair<A, B> create(A left, B right) {
        return new Pair<A, B>(left, right);
    } // end factory method

    @Override
    public final boolean equals(Object o) {
        if (!(o instanceof Pair<?,?>))
            return false;

        final Pair<?, ?> other = (Pair<?, ?>) o;
        return equal(getLeft(), other.getLeft()) && equal(getRight(), other.getRight());
    } // end method

    public static final boolean equal(Object o1, Object o2) {
        if (o1 == null) {
            return o2 == null;
        }
        return o1.equals(o2);
    } // end method

    @Override
    public int hashCode() {
        int hLeft = getLeft() == null ? 0 : getLeft().hashCode();
        int hRight = getRight() == null ? 0 : getRight().hashCode();

        return hLeft + (37 * hRight);
    } // end method

    @Override
    public String toString() {
        StringBuilder sb = new StringBuilder();
        sb.append('<');
        if( left == null ) {
            sb.append("null");
        } else {
            sb.append(left.toString());
        } // end if
        sb.append(',');
        if( right == null ) {
            sb.append("null");
        } else {
            sb.append(right.toString());
        } // end if
        sb.append('>');
        return sb.toString();
    } // end method
} // end class
like image 30
harschware Avatar answered Sep 22 '22 01:09

harschware


I just ran into this problem myself, and in my -particular- case, I didn't need to know the type E.

For example:

public class Example<E> {
    E value;

    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Example<?> other = (Example<?>) obj;
        if (value == null) {
            if (other.value != null)
                return false;
        } else if (!value.equals(other.value))
            return false;
        return true;
    }
}

In the above code, there is no unchecked cast because of using Example<?>. The type parameter wildcard '?' saves the day.

like image 38
jfritz42 Avatar answered Sep 23 '22 01:09

jfritz42