Search code examples
javagenericstype-erasure

How do I implement equals for generic types?


Suppose I have a generic container type like this:

public final class Container<T> {

    public final T t;

    public Container(final T t) {
        this.t = t;
    }
}

I want to implement equals such that this passes:

final Container<Object> a = new Container<>("Hello");
final Container<String> b = new Container<>("Hello");

assertNotEquals(a, b);

The instances a and b should be different because their type parameter T is different.

However, due to erasure, this is tricky to do. This implementation, for example, is incorrect:

@Override
public boolean equals(final Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj != null && obj instanceof Container<?>) {
        final Container<?> other = (Container<?>)obj;
        return Objects.equals(this.t, other.t);
    }
    return false;
}

I expect that I will need to store some kind of token for T.

How do I implement equals for generic types?


This does not answer the question.


Solution

  • you can modify a little the Container class and add this field:

    public final Class<T> ct;
    

    with that and the equals override then

    System.out.println(a.equals(b));
    

    will return false because the equals method will check Class<String> vs Class<Object>

    class Container<T> {
    
        public final T t;
        public final Class<T> ct;
    
        public Container(final T t, Class<T> ct) {
            this.t = t;
            this.ct = ct;
        }
    
        @Override
        public int hashCode() {
            final int prime = 31;
            int result = 1;
            result = (prime * result) + ((ct == null) ? 0 : ct.hashCode());
            result = (prime * result) + ((t == null) ? 0 : t.hashCode());
            return result;
        }
    
        @Override
        public boolean equals(Object obj) {
            if (this == obj)
                return true;
            if (obj == null)
                return false;
            if (getClass() != obj.getClass())
                return false;
            Container other = (Container) obj;
            if (ct == null) {
                if (other.ct != null)
                    return false;
            } else if (!ct.equals(other.ct))
                return false;
            if (t == null) {
                if (other.t != null)
                    return false;
            } else if (!t.equals(other.t))
                return false;
            return true;
        }
    
    }