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.
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;
}
}